PEFT documentation
ShadowPEFT
ShadowPEFT
ShadowPEFT bổ sung cho một mô hình decoder-only cơ sở đã đóng băng một mạng shadow nhẹ, có thể huấn luyện trước chạy song song với backbone. Một backbone shadow nhỏ tạo ra trạng thái shadow ban đầu s^(0), sau đó trạng thái này đi theo vòng lặp decoder của mô hình cơ sở: tại mỗi khối được nhắm tới, sự chênh lệch giữa các trạng thái ẩn của mô hình cơ sở và trạng thái shadow được tiêm ngược vào đầu vào của khối (một hiệu chỉnh hạng thấp), và trạng thái shadow được cập nhật bằng một cập nhật residual có cổng được tính từ đầu ra của khối. Chỉ các thành phần shadow được huấn luyện; mô hình cơ sở vẫn giữ nguyên trạng thái đóng băng.
Input
├──► Shadow backbone (small, trainable) ──► s^(0)
└──► Base model (frozen, large)
block_0 ◄── inject(h, s) ─► h_0 ──► update ─► s_1
block_1 ◄── inject(h, s) ─► h_1 ──► update ─► s_2
... (the (hidden, shadow) pair rides the loop together)Vì quá trình thích ứng là một quỹ đạo phụ thuộc vào đầu vào trong không gian lớp (trạng thái bóng tiến hóa cùng với dữ liệu) chứ không phải là một delta tĩnh trong không gian trọng số, ShadowPEFT không thể được hợp nhất vào trọng số gốc. Việc gọi merge, merge_adapter hoặc merge_and_unload sẽ gây ra một lỗi rõ ràng. Đối với các mô hình ngôn ngữ Transformers, bạn có thể lấy mạng bóng nhẹ độc lập bằng cách sử dụng model.base_model.unload_shadow(), hàm này trả về một DetachedShadowModel độc lập. Việc unloading độc lập không được hỗ trợ cho các mô hình Diffusers vì việc tái tạo một denoiser hoàn chỉnh phụ thuộc vào kiến trúc cụ thể.
Việc thêm nhiều adapter, chuyển đổi giữa chúng bằng set_adapter, xóa chúng, và bật/tắt chúng đều hoạt động giống như với các phương pháp PEFT khác. Chỉ có một adapter có thể hoạt động tại một thời điểm, vì trạng thái bóng (shadow state) là một quỹ đạo duy nhất xuyên qua mạng.
Khung xương bóng (shadow backbone) có thể được xây dựng theo hai cách, được điều khiển bởi ShadowConfig.shadow_model:
"mirror"(mặc định): một backbone bóng nhỏ hơn được tạo ra tự động. Các mô hình ngôn ngữ sử dụng một bản sao rút gọn của kiến trúc cơ sở. Các kiến trúc Diffusers có backend được đăng ký sẽ sử dụng một mô hình tương tự kiến trúc rút gọn được khởi tạo từ các trọng số cơ sở được chọn; các kiến trúc tương thích không có backend sẽ chuyển sang sử dụng MLP dư theo từng token. Khi kích thước ẩn của bản bóng khác với kích thước của bản cơ sở, một phép chiếu đã được huấn luyện sẽ cầu nối khoảng cách đó.- một id mô hình hoặc đường dẫn cục bộ: backbone được tải dưới dạng một mô hình pre-trained nhỏ hơn. Các mô hình Transformers sử dụng
AutoModel; các backend Diffusers đã đăng ký định nghĩa việc tải checkpoint tương thích của riêng chúng.
Hỗ trợ Diffusers nhận diện kiến trúc được chọn tự động từ lớp mô hình. Flux2 hiện có một backend đã đăng ký; các mô hình Diffusers dựa trên transformer tương thích khác sử dụng phương án dự phòng MLP chung. Việc gọi unload_shadow() độc lập vẫn chưa được hỗ trợ cho tất cả các mô hình Diffusers vì việc tái tạo một denoiser hoàn chỉnh phụ thuộc vào kiến trúc cụ thể.
So với các phương pháp kiểu LoRA, ShadowPEFT bổ sung thêm tham số và tính toán (chạy một mạng song song và bao bọc toàn bộ các khối decoder), nhưng adapter là một mạng tự chứa có thể được huấn luyện tập trung, tái sử dụng giữa các tác vụ và khởi tạo từ một mô hình nhỏ đã được huấn luyện trước. Một tổn thất phụ tùy chọn (auxiliary_loss_weight) áp dụng đầu tác vụ lên trạng thái bóng ban đầu s^(0) và cộng nó vào tổn thất tác vụ, khuyến khích đường bóng có thể tách rời giải quyết tác vụ một cách độc lập. Đối với LM nhân quả, đầu output cơ sở được tái sử dụng; bao gồm "lm_head" trong modules_to_save để huấn luyện và lưu trữ nó thông qua cơ chế PEFT tiêu chuẩn.
Bộ đệm KV
ShadowPEFT hỗ trợ giải mã tăng dần với bộ đệm KV dual: một cho mô hình cơ sở đóng băng và một cho khung xương bóng. Việc tiêm/cập nhật là cục bộ theo token, nên một token mới chỉ cần trạng thái bóng riêng của nó s; tính nhân quả giữ cho các khóa/giá trị tiền tố cơ sở (được tính dưới chế độ tiêm) vẫn hợp lệ. Đối tượng ghép đôi là ShadowCache, được trả về dưới dạng past_key_values khi use_cache=True. Bạn có thể truyền use_cache=True vào generate() như bình thường.
out = model.generate(input_ids, max_new_tokens=32) # dual KV cache enabled by default
# or explicitly:
out = model.generate(input_ids, use_cache=True, max_new_tokens=32)use_cache=False vẫn hoạt động và xử lý lại toàn bộ chuỗi ở mỗi bước (hữu ích cho việc gỡ lỗi).
Cách sử dụng
from transformers import AutoModelForCausalLM
from peft import ShadowConfig, get_peft_model
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
config = ShadowConfig(r=8, shadow_num_hidden_layers=1, task_type="CAUSAL_LM")
model = get_peft_model(model, config)
model.print_healthcheck()
out = model.generate(input_ids, max_new_tokens=32)Để khởi tạo shadow backbone từ một mô hình pre-trained nhỏ hơn, hãy truyền id hoặc đường dẫn của nó vào shadow_model:
config = ShadowConfig(shadow_model="Qwen/Qwen3-0.6B", task_type="CAUSAL_LM")
model = get_peft_model(base_model, config)Đánh giá đường dẫn bóng
Mặc định, đầu ra của mô hình (logits) là mô hình cơ bản đã thích ứng bóng: các hiệu chỉnh bóng được tiêm vào trạng thái ẩn của mô hình cơ bản ở mỗi lớp, do đó logits đã phản ánh ShadowPEFT (dùng model.disable_adapter() để lấy mô hình cơ bản thuần túy nhằm so sánh). Mất phụ trợ ngoài ra còn huấn luyện đường bóng để tự giải quyết tác vụ.
Để đánh giá mạng bóng độc lập cho một mô hình ngôn ngữ Transformers (mô hình nhẹ, có thể tách rời —
tương đương của merge_and_unload trong ShadowPEFT), hãy sử dụng unload_shadow(). Phương thức này trả về head(projection(backbone(x))) dưới dạng một mô hình tác vụ thông thường mà bạn có thể đánh giá như bất kỳ mô hình nào khác: đối với tác vụ causal-LM, nó là
một causal LM có khả năng sinh (hỗ trợ generate() và bộ nhớ đệm KV), còn đối với tác vụ phân loại chuỗi, nó sẽ gom
token cuối cùng và trả về logits của các lớp. Việc gọi phương thức này cho một mô hình Diffusers sẽ gây ra NotImplementedError.
shadow = model.base_model.unload_shadow() # a DetachedShadowModel (a PreTrainedModel)
shadow.eval()
# causal LM:
out = shadow.generate(input_ids, max_new_tokens=32)
# sequence classification:
logits = shadow(input_ids=input_ids, attention_mask=attention_mask).logits # (batch, num_labels)Mặc định (copy=False), model được trả về chia sẻ các module của nó với model PEFT, và một shadow backbone chia sẻ các input embeddings gốc đã đóng băng sẽ tiếp cận chúng thông qua một tham chiếu không phải là submodule. Điều này không thành vấn đề cho việc đánh giá, nhưng nó có nghĩa là save_pretrained sẽ ghi một checkpoint không có bảng embedding. Truyền copy=True khi bạn muốn lưu hoặc đẩy model độc lập:
shadow = model.base_model.unload_shadow(copy=True)
shadow.save_pretrained("standalone-shadow")API
ShadowConfig
lớp peft.ShadowConfig
< source >( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falsetarget_modules: list[str] | str | None = Noneexclude_modules: list[str] | str | None = Noner: int = 8shadow_alpha: float = 0.1shadow_dropout: float = 0.2init_weights: bool = Trueshadow_model: str = 'mirror'shadow_num_hidden_layers: int | None = Noneshadow_hidden_size: int | None = Noneshadow_num_attention_heads: int | None = Noneshadow_intermediate_size: int | None = Noneshare_embeddings: bool = Trueupdate_hidden_size: int | None = Noneauxiliary_loss_weight: float = 0.05layers_to_transform: list[int] | int | None = Nonelayers_pattern: list[str] | str | None = Nonemodules_to_save: list[str] | None = None )
Tham số
- target_modules (
Optional[Union[list[str], str]]) — Các khối transformer cần bọc bằng cơ chế shadow (các khối decoder hoàn chỉnh, không phải các lớp linear). Có thể là một danh sách tên module, hoặc một regex, ví dụr'.*\.layers\.\d+$'để nhắm đến mọi khối decoder. Mặc định làNone, khi đó mọi khối decoder của mô hình cơ sở sẽ được bọc. Lưu ý rằng các khối được bọc phải liên tục, vì trạng thái shadow chạy dọc theo vòng lặp decoder từ khối được bọc đầu tiên đến khối cuối cùng. - exclude_modules (
Optional[Union[list[str], str]]) — Tên của các module không được bọc bằng cơ chế shadow, được cung cấp dưới dạng danh sách hoặc regex. Mặc định làNone. - r (
int) — Rank của bottleneck tiêm low-rankW_down/W_up. Mặc định là8. - shadow_alpha (
float) — Độ mạnh của phần hiệu chỉnh được chèn thêm vào đầu vào của khối (Phương trình 4). Mặc định là0.1. - shadow_dropout (
float) — Xác suất dropout được áp dụng cho tín hiệu sai lệch trước bottleneck (Phương trình 3). Mặc định là0.2. - init_weights (
bool) — Có nên khởi tạo bằng khôngW_upđể việc tiêm không có tác dụng ở đầu quá trình huấn luyện (giống quy ướcB=0của LoRA). Không thay đổi tham số này trừ khi bạn biết rõ mình đang làm gì. Mặc định làTrue. - shadow_model (
str) — Cách xây dựng bộ khung shadow."mirror"(mặc định) xây dựng một bộ khung mới có cùng kiến trúc với mô hình gốc nhưng có ít lớp hơn/lớp nhỏ hơn (xem các ghi đèshadow_*bên dưới). Các kiến trúc Diffusers có backend Shadow được đăng ký sẽ sử dụng mô hình có kiến trúc tương tự nhưng đã được giảm; các diffusion transformer tương thích khác sẽ chuyển sang MLP theo từng token. Bất kỳ chuỗi nào khác đều được coi là model id hoặc đường dẫn cục bộ. Điểm kiểm tra shadow Transformers dạng “projected” (model_type == "causal_lm_with_hidden_projection", ví dụshadow-llm/Qwen3-0.6B-H8B) sẽ tải bộ khung được huấn luyện trước cùng với phép chiếu shadow-hidden -> base-hidden đã được huấn luyện. Các điểm kiểm tra Diffusers rõ ràng yêu cầu backend được đăng ký; hiện tại Flux2 được hỗ trợ. - shadow_num_hidden_layers (
Optional[int]) — Độ sâu của backbone bóng (shadow) tự động xây dựng ("mirror"). Đối với Flux2, điều này tạo ra số lượng khối double-stream được yêu cầu và gấp đôi số lượng khối single-stream; đối với phương án dự phòng Diffusers chung, đây là số lượng khối residual MLP. Mặc định làNone(1lớp). - shadow_hidden_size (
Optional[int]) — Kích thước ẩn của bộ khung shadow được xây dựng tự động; có thể khác với kích thước ẩn cơ bản (một phép chiếu sẽ được chèn tự động). Các backend kiến trúc có thể áp đặt thêm các ràng buộc; các phép giảm của Flux2 phải bảo toàn chiều đầu chú ý cơ bản của nó. Mặc định làNone(giống với mô hình cơ bản). - shadow_num_attention_heads (
Optional[int]) — Số lượng đầu attention của bộ khung shadow được xây dựng tự động. Mặc định làNone(giống với mô hình cơ sở). Tùy chọn này được sử dụng bởi các backend nhận diện kiến trúc nhưng không được sử dụng bởi phương án dự phòng MLP chung của Diffusers. - shadow_intermediate_size (
Optional[int]) — Chiều rộng feed-forward của shadow backbone được tự động xây dựng. Mặc định làNone(giống với hidden size của nó đối với phương án dự phòng MLP chung của Diffusers). - share_embeddings (
bool) — Có nên tái sử dụng các embedding đầu vào gốc đã đóng băng để cung cấp cho bộ khung xương bóng (quainputs_embeds) thay vì bảng embedding riêng của bộ khung xương bóng hay không. Mặc định làTrue. - update_hidden_size (
Optional[int]) — Chiều rộng ẩn của các MLP cập nhậtT(ứng viên) vàG(cổng). Mặc định làNone(sử dụngr). - auxiliary_loss_weight (
float) — Trọng sốlambdacủa auxiliary shadow loss (Eq. 8-9) được cộng vào task loss khilabelsđược truyền vào. Các vòng lặp huấn luyện Diffusion có thể sử dụng cùng giá trị này cho detached denoising loss. Đặt thành0để tắt tính năng này. Mặc định là0.05. - layers_to_transform (
Optional[Union[list[int], int]]) — Các chỉ số khối cần biến đổi. Nếu truyền vào một danh sách, cơ chế shadow sẽ được áp dụng cho các khối tại những chỉ số đó. Nếu truyền vào một số nguyên duy nhất, nó chỉ được áp dụng tại chỉ số đó. Mặc định làNone(mọi khối khớp đều được biến đổi). - layers_pattern (
Optional[Union[list[str], str]]) — Tên mẫu lớp, chỉ được sử dụng nếulayers_to_transformkhácNone. Đây là tên củann.ModuleListchứa các khối decoder (thường là"layers"hoặc"h"). Mặc định làNone. - modules_to_save (
Optional[list[str]]) — Các module bổ sung cần được đặt ở chế độ có thể huấn luyện và lưu trong checkpoint cuối cùng (ví dụ"lm_head"hoặc một đầu phân loại). Mặc định làNone.
Lớp cấu hình cho ShadowModel (ShadowPEFT).
ShadowPEFT bổ sung một mạng shadow song song nhỏ, có thể huấn luyện, vào một mô hình decoder-only cơ bản đã được đóng băng. Một backbone shadow tạo ra trạng thái shadow ban đầu s^(0), sau đó trạng thái này đi theo vòng lặp decoder của mô hình cơ bản: tại mỗi khối được nhắm tới, sự khác biệt giữa các trạng thái ẩn của mô hình cơ bản và trạng thái shadow được tiêm ngược lại vào đầu vào của khối (Phương trình 2-4), và trạng thái shadow được cập nhật bằng một cập nhật residual có cổng từ đầu ra của khối (Phương trình 5-7). Chỉ các thành phần shadow được huấn luyện; mô hình cơ bản vẫn được giữ nguyên. Vì sự thích ứng là một quỹ đạo phụ thuộc vào đầu vào trong không gian lớp chứ không phải là một delta trọng số tĩnh, ShadowPEFT không thể được hợp nhất vào các trọng số cơ bản.
ShadowModel
lớp peft.ShadowModel
< source >( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None )
Tạo một mô hình ShadowPEFT từ một mô hình transformers được huấn luyện trước.
ShadowPEFT bổ sung một mạng shadow song song nhỏ, có thể huấn luyện, vào một mô hình decoder-only cơ bản đã đóng băng. Một backbone shadow tạo ra trạng thái shadow ban đầu, di chuyển cùng vòng lặp decoder cơ bản; tại mỗi khối được nhắm tới, sự khác biệt giữa các trạng thái ẩn cơ bản và trạng thái shadow được đưa vào khối đó, và trạng thái shadow được cập nhật bằng một cập nhật residual có cổng. Chỉ các thành phần shadow được huấn luyện. Xem ShadowConfig để biết cấu hình.
Phương pháp này không thể được hợp nhất vào trọng số gốc (sự thích ứng là một quỹ đạo phụ thuộc vào đầu vào, không phải là một delta trọng số tĩnh); hãy sử dụng ShadowModel.unload_shadow() để lấy mạng shadow độc lập thay thế.
Mất của chính nhiệm vụ cho đường dẫn bóng, CE(shadow_head(s^(0)), labels) (không trọng số; forward áp dụng trọng số).
Mất mát được tính trên trạng thái bóng ban đầu s^(0) (đầu ra của khung xương bóng, đã được chiếu) — chính xác là những gì mô hình unload_shadow() độc lập tính toán dưới dạng head(projection(backbone(x))). Điều này làm cho mạng bóng tách rời có thể sử dụng độc lập; việc huấn luyện nó trên s^(L) (trạng thái cuối cùng, phụ thuộc vào đầu ra theo từng lớp của mô hình cơ sở và không tồn tại độc lập) sẽ khiến mô hình tách rời không được huấn luyện.
unload_shadow
< source >( adapter_name: str | None = Nonecopy: bool = False )
Tham số
- adapter_name (
str, tùy chọn) — Adapter mà mạng lưới bóng (shadow network) của nó sẽ được unmount. Mặc định là adapter đang hoạt động. - copy (
bool, tuỳ chọn, mặc định làFalse) — NếuTrue, sao chép sâu mô hình được trả về để nó độc lập với mô hình này (dùng nhiều bộ nhớ hơn). NếuFalse(mặc định), chia sẻ các module — tương tự nhưmerge_and_unload, vốn tái sử dụng các module thay vì nhân bản chúng. Việc thay đổi một mô hình sẽ ảnh hưởng đến mô hình kia.
Trả về bộ khung bóng (+ đầu) như một mô hình độc lập, mà không có mô hình cơ sở.
Bản tương đương của merge_and_unload trong ShadowPEFT: trong khi hàm đó trả về mô hình cơ sở với các thích ứng đã được tích hợp sẵn, hàm này chỉ trả về mạng shadow nhẹ để suy luận hiệu quả cao / trên thiết bị biên. Nó thực thi head(projection(backbone(x))) — các cập nhật theo khối yêu cầu đầu ra của mô hình cơ sở nên không tồn tại độc lập. Đối với mô hình ngôn ngữ, kết quả hoạt động như một LM nhân quả thông thường (hỗ trợ generate() và bộ nhớ đệm KV). Các mô hình Diffusers không được hỗ trợ vì việc tái tạo một bộ khử nhiễu độc lập hoàn chỉnh là cụ thể cho từng kiến trúc khuếch tán.
Gán kết quả cho một biến và sử dụng nó; với copy=False, các module vẫn được chia sẻ với model này.
Truyền copy=True khi bạn có ý định save_pretrained mô hình độc lập. Một shadow backbone chia sẻ các input embeddings của base đã đóng băng (cấu hình mặc định "mirror") truy cập chúng thông qua một tham chiếu không phải là submodule của mô hình được trả về, do đó checkpoint với copy=False sẽ thiếu bảng embedding; copy=True sẽ gắn lại một bản sao riêng và lưu một checkpoint hoàn chỉnh.
ShadowCache
Bộ đệm KV ghép cặp cho việc giải mã ShadowPEFT tăng dần.
Việc tạo tự hồi quy (autoregressive generation) cần một bộ nhớ đệm (cache) của mô hình cơ sở (các khóa/giá trị được tính toán dưới sự tiêm bóng) và một bộ nhớ đệm mô hình bóng riêng biệt (để tiến hành từng token của s^(0)). Đây là một lớp con của Cache trong Transformers: các thao tác ảnh hưởng đến bố cục lô (batch) hoặc chuỗi (sequence) (reset, reorder, crop, repeat và select) được áp dụng cho cả hai bộ nhớ đệm, trong khi metadata chú ý (attention) và các bản cập nhật được ủy quyền cho bộ nhớ đệm cơ sở. Các thuộc tính cache không xác định cũng được ủy quyền cho bộ nhớ đệm cơ sở để đảm bảo tương thích với các triển khai cache cụ thể cho từng kiến trúc.
Wrapper được cố ý không cho phép compile vì hai cache có thể có bố cục lớp và kích thước ẩn khác nhau. Việc chuyển đổi tuple legacy không được hỗ trợ, vì một tuple legacy duy nhất không thể biểu diễn cả hai đường dẫn. Nửa shadow được giải nén trước khi thực hiện forward của base và được đóng gói lại khi ra — xem hook của ShadowModel.