Transformers documentation

Pemuatan bobot dinamis

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Pemuatan bobot dinamis

Checkpoint sering kali diserialisasi dalam format yang tidak sesuai dengan yang diharapkan model saat runtime. Skenario umum meliputi:

  1. Bobot terfusi: Checkpoint menyimpan bobot gate_proj dan up_proj secara terpisah, tetapi model menggunakan gate_up_proj yang terfusi untuk efisiensi.
  2. Konsolidasi pakar MoE: Bobot pakar individual (experts.0.weight, experts.1.weight, …) perlu ditumpuk menjadi satu tensor 3D.
  3. Penamaan lama: Checkpoint lama menggunakan konvensi penamaan yang berbeda (misalnya, LayerNorm.gamma vs LayerNorm.weight).
  4. Model komposit: Model bahasa-visi berisi dua sub-modul PreTrainedModel, masing-masing dengan konvensi checkpoint-nya sendiri.
  5. Kuantisasi: Bobot mungkin disimpan dalam format terkuantisasi yang memerlukan deserialisasi.

Dynamic weight loading mengatasi hal ini dengan menerapkan operasi terjadwal yang dapat dibalik pada tensor checkpoint saat dimuat. Transformers menyediakan fitur ini melalui WeightConverter dan WeightRenaming, yang menjelaskan bagaimana satu atau beberapa kunci checkpoint dipetakan ke satu atau beberapa parameter model, serta ConversionOps yang dapat dikomposisikan mana yang harus dijalankan pada tensor yang cocok. Pendekatan ini beradaptasi dengan tata letak bobot baru, mendukung mixture-of-experts (MoE) yang terkuantisasi, dan terintegrasi dengan tensor parallelism.

Panduan ini menunjukkan cara menggunakan WeightConverter untuk mengonversi tensor. Pemetaan konversi terdapat di conversion_mapping.py; pemetaan yang terdaftar menggunakan kunci berupa string model_type (misalnya "mixtral") atau nama kelas (misalnya "LlavaModel").

Pipeline pemuatan penuh

Semua model melewati sistem pemuatan bobot dinamis. Pemetaan konversi adalah langkah opsional dalam sistem tersebut yang hanya diaktifkan ketika model memiliki entri yang terdaftar untuk nama kelasnya atau model_type.

Checkpoint File → from_pretrained() → convert_and_load_state_dict_in_model()
                                              ↓
                         ┌───────────────────────────────────────────────────────────┐
                         │  For each weight in checkpoint:                           │
                         │  1. Match renamed/processed source key to model parameter │
                         │  2. Shard the weight and send to device (async)           │
                         │  3. Collect tensors with the same source_pattern together │
                         │     (e.g. MoE experts, gate_up_proj)                      │
                         │  4. Apply dequantization/deserialization (if pre-quant)   │
                         │  5. Apply conversion (if defined)                         │
                         │  6. Apply quantization (if enabled and step 4 not used)   │
                         │  7. Set parameter on model                                │
                         └───────────────────────────────────────────────────────────┘
LangkahSaat diaktifkan
Pemuatan dinamisSelalu, untuk semua model
Pemetaan konversiHanya ketika kelas model atau model_type terdaftar di _MODEL_TO_CONVERSION_PATTERN
Sharding TPHanya ketika DistributedConfig(tp_size=N) digunakan dan model memiliki base_model_tp_plan
Dequantisasi/deserialisasiHanya saat memuat checkpoint yang sudah terkuantisasi
KuantisasiHanya ketika konfigurasi kuantisasi disediakan dan bobot belum terkuantisasi sebelumnya

Model padat (misalnya, Llama)

Untuk sebagian besar model dense, format checkpoint secara langsung sesuai dengan format model, sehingga pemetaan konversi tidak diperlukan. Beberapa model mungkin masih memerlukan penamaan ulang (misalnya, konvensi penamaan lama). Sharding TP tetap berlaku saat diaktifkan.

Checkpoint:                             Model:
model.layers.0.self_attn.q_proj.weight  →  model.layers.0.self_attn.q_proj.weight
model.layers.0.self_attn.k_proj.weight  →  model.layers.0.self_attn.k_proj.weight
model.layers.0.mlp.gate_proj.weight     →  model.layers.0.mlp.gate_proj.weight
model.layers.0.mlp.up_proj.weight       →  model.layers.0.mlp.up_proj.weight
model.layers.0.mlp.down_proj.weight     →  model.layers.0.mlp.down_proj.weight

Checkpoint lama mungkin menggunakan konvensi penamaan yang lebih lama, yang ditangani oleh penamaan ulang bawaan yang diterapkan ke semua model:

Checkpoint:                          Model:
LayerNorm.gamma              →       LayerNorm.weight
LayerNorm.beta               →       LayerNorm.bias

Model MoE (misalnya, Mixtral)

Untuk model MoE, format checkpoint berbeda dari format model. Pemetaan konversi mengubah bobot ahli yang terpisah menjadi tensor 3D yang digabungkan, dan sharding TP diterapkan setelah konversi.

Checkpoint:                              Model:
experts.0.w1.weight  ─┐
experts.1.w1.weight   │ MergeModulelist
...                   ├───────────────→  experts.gate_up_proj (8, hidden, 2*intermediate)
experts.0.w3.weight   │ + Concatenate
experts.1.w3.weight  ─┘

Model komposit (misalnya, visi-bahasa)

Sebuah PreTrainedModel dapat berisi sub-modul PreTrainedModel lainnya. Setiap sub-model dapat memiliki pemetaan konversi miliknya sendiri, yang didaftarkan berdasarkan nama kelasnya atau model_type-nya. Ketika model induk dimuat, get_model_conversion_mapping menelusuri sub-model dalam urutan depth-first, mengumpulkan pemetaan mereka, dan secara otomatis membatasi ruang lingkup setiap transformasi ke jalur sub-modulnya melalui scope_prefix.

Composite model:                              Per-submodel mappings (auto-scoped):
LlavaForConditionalGeneration
├── vision_model: SiglipVisionModel    →     SiglipVisionModel mapping (scope="vision_model")
└── language_model: LlamaForCausalLM   →     LlamaForCausalLM mapping  (scope="language_model")

scope_prefix adalah jalur bertitik dari sub-modul ("vision_model", "language_model.model", dst.). Transformasi berscope hanya dipicu pada kunci yang diawali dengan f"{scope_prefix}."; prefix dihapus sebelum pencocokan pola dan dilampirkan kembali setelah substitusi, sehingga pemetaan untuk setiap sub-model ditulis relatif terhadap sub-model tersebut, persis seolah-olah sub-model itu adalah root.

Arsitektur

Sistem ini dibangun di sekitar beberapa komponen utama yang didefinisikan dalam core_model_loading.py:

Fase 1 — Pemrosesan per kunci (mengiterasi kunci checkpoint):

  1. Lewati daftar transform sekali. Setiap WeightRenaming yang cocok akan dipicu (mis. block_sparse_moe → mlp), dan hanya satu WeightConverter yang dapat mengklaim kunci tersebut (mis. experts.*.w1.weight).
  2. Shard (TP) dan kirim ke perangkat secara asinkron melalui ThreadPoolExecutor.
  3. Kumpulkan tensor dengan source_pattern yang sama secara bersama-sama (misalnya semua bobot pakar MoE, proyeksi gate + up).

Fase 2 — Pemrosesan per pemetaan (mengiterasi pemetaan yang dikumpulkan):

  1. Dequantize/deserialize (hanya untuk checkpoint yang sudah terkuantisasi sebelumnya).
  2. Terapkan rantai ConversionOps: Chunk, Concatenate, MergeModulelist, Transpose, dll.
  3. Kuantisasi secara langsung (jika belum dikuantisasi sebelumnya).
  4. Set parameter pada model.

WeightTransform

Kelas dasar yang menangani pencocokan pola dan pengumpulan tensor:

  • Kompilasi pola: Pola sumber adalah ekspresi reguler penuh yang dicocokkan dengan re.search(). Wildcard * mencocokkan komponen yang dapat diindeks apa pun dan mengelompokkan semua kecocokan untuk operasi batch.
  • Grup penangkap & referensi balik: Grup penangkap dalam pola sumber dapat dirujuk sebagai \1, \2, … dalam pola target untuk mempertahankan substring (misalnya indeks layer) selama proses penamaan ulang.
  • Penentuan ruang lingkup: scope_prefix (diatur secara otomatis per sub-model oleh get_model_conversion_mapping) membatasi transformasi pada kunci di bawah path tersebut. Prefiks dihapus sebelum pencocokan dan dilekatkan kembali setelah substitusi.
  • Penamaan ulang kunci: rename_source_key() menerapkan regex (dengan penanganan scope) dan mengembalikan (renamed_key, source_pattern) agar loader mengetahui konverter mana, jika ada, yang mengklaim kunci tersebut.
  • Koleksi tensor: add_tensor() mengakumulasi tensor yang telah di-resolve (atau Future) berdasarkan source_pattern mereka, sehingga semua tensor yang dibutuhkan oleh satu konversi (misalnya semua bobot pakar MoE) di-batch bersama sebelum rantai operasi dijalankan.
  • Reversibilitas: reverse_transform() menukar pola sumber ↔ target dan membalik setiap operasi, sehingga daftar yang sama jika dibalik akan menggerakkan proses penyimpanan.
  • Tracking: was_used() melaporkan apakah transform benar-benar cocok dengan kunci mana pun selama proses loading; hal ini diperlukan agar penamaan ulang yang tidak bijektif (misalnya PrefixChange yang menambahkan prefiks yang mungkin sudah ada) dapat diterapkan secara simetris saat penyimpanan.

WeightRenaming

WeightRenaming adalah WeightTransform khusus untuk penggantian nama kunci murni tanpa operasi tensor. Berbeda dengan WeightConverter, WeightRenaming tidak claim kuncinya, sehingga beberapa penggantian nama dapat dirangkai secara bebas. Pada jalur load, semua penggantian nama dijalankan sebelum converter; pada jalur save (daftar terbalik), semua penggantian nama terbalik dijalankan setelah converter terbalik — lihat aturan urutan di atas.

# Legacy checkpoint compatibility
WeightRenaming("LayerNorm.gamma", "LayerNorm.weight")

# Module path changes
WeightRenaming(".block_sparse_moe.", ".mlp.")

PrefixChange adalah wrapper tingkat lebih tinggi di atas WeightRenaming untuk kasus umum berupa penghapusan atau penambahan seluruh komponen path. Parameter opsional model_prefix membatasi operasi pada key di bawah namespace tersebut:

# "model.layers.bad_prefix.weight" → "model.layers.weight"
PrefixChange(prefix_to_remove="bad_prefix", model_prefix="model.layers")
# "layers.0.weight" → "model.layers.0.weight"
PrefixChange(prefix_to_add="model")

WeightConverter

WeightConverter memperluas WeightTransform dengan rantai ConversionOps yang bekerja pada tensor yang dikumpulkan. Keempat kardinalitas yang didukung adalah:

KardinalitasPola sumberPola targetOperasi tipikal
satu-ke-satu11Transpose, PermuteForRope
satu-ke-banyak1>1Chunk (misalnya, unpack qkv_proj)
banyak-ke-satu>11Concatenate, MergeModulelist (misalnya, gabungkan para ahli)
banyak-ke-banyak>1>1hanya dengan operasi yang secara eksplisit mendukungnya (misalnya ErnieFuseAndSplitTextVisionExperts)
WeightConverter(
    source_patterns=[".experts.*.w1.weight", ".experts.*.w3.weight"],
    target_patterns=".experts.gate_up_proj",
    operations=[MergeModulelist(dim=0), Concatenate(dim=1)],
)

WeightConverter juga dapat dibalik: reverse_transform() menukar sumber ↔ target dan mengganti setiap operasi dengan reverse_op-nya, sehingga pemetaan konversi yang terdaftar bersifat dua arah secara bawaan (pemuatan menggunakan daftar apa adanya, penyimpanan menggunakannya secara terbalik).

Urutan penamaan ulang dan konverter

Daftarkan entri WeightRenaming sebelum entri WeightConverter, dan pastikan daun-daunnya saling terpisah: rename menormalisasi kunci yang dikonsumsi oleh converter, tetapi tidak pernah menargetkan daun yang dihasilkan oleh converter. Jalur penyimpanan bergantung pada hal ini untuk membalikkan pemetaan dalam dua fase (balikkan converter, lalu balikkan rename).

Daftar transformasi diproses secara berurutan, satu kali untuk setiap kunci checkpoint. Untuk setiap kunci:

  • Setiap WeightRenaming yang cocok akan dipicu; beberapa penamaan ulang dapat berantai.
  • The first WeightConverter yang claims kunci tersebut. Konverter berikutnya dilewati — hal ini menjamin tensor diarahkan ke satu konverter untuk langkah merge/split, dan inilah alasan mengapa dua konverter dengan maksud yang tumpang tindih merupakan konfigurasi yang salah.
weight_mapping = [
    WeightRenaming("^old_prefix", "encoder"),              # rename runs always
    WeightConverter(                                       # converter claims the key
        "attn.qkv_proj.weight",
        ["attn.q_proj.weight", "attn.k_proj.weight", "attn.v_proj.weight"],
        operations=[Chunk(dim=0)],
    ),
]
# Load:  "old_prefix.attn.qkv_proj.weight"
#   → WeightRenaming  → "encoder.attn.qkv_proj.weight"
#   → WeightConverter → "encoder.attn.{q,k,v}_proj.weight"
#
# Save: list reversed, each transform inverted:
#   → rev(WeightConverter) repacks QKV → "encoder.attn.qkv_proj.weight"
#   → rev(WeightRenaming)  fixes prefix → "old_prefix.attn.qkv_proj.weight"

Operasi konversi

Kelas WeightConverter memiliki beberapa operasi yang dijalankan saat from_pretrained() dipanggil untuk mengubah tensor sumber checkpoint menjadi tensor target model.

Operasi sepenuhnya dapat dibalik. Menyimpan akan membalikkan konversi dan mengembalikan checkpoint asli sehingga Anda dapat dengan mudah bekerja di berbagai framework.

OperasiBalik
Chunk(dim)Concatenate(dim)
Concatenate(dim)Chunk(dim)
MergeModulelist(dim)SplitModulelist(dim)
SplitModulelist(dim)MergeModulelist(dim)
Transpose(d0, d1)Transpose(d1, d0)
PermuteForRope()PermuteForRope()
Conv3dToLinear(...)LinearToConv3d(...)

Chunk

Operasi Chunk membagi tensor menjadi bagian-bagian yang sama besar sepanjang satu dimensi. Misalnya, jika sebuah model mengharapkan Q, K, dan V sebagai tiga tensor terpisah, bukan sebagai satu tensor tunggal.

WeightConverter(
    "self_attn.qkv_proj",
    ["self_attn.q_proj", "self_attn.k_proj", "self_attn.v_proj"],
    operations=[Chunk(dim=0)],
)

Gabungkan

Operasi Concatenate menggabungkan tensor yang terpisah menjadi satu tensor tunggal. Misalnya, jika sebuah model mengharapkan Q, K, dan V sebagai satu tensor tunggal, bukan sebagai tensor yang terpisah.

WeightConverter(
    ["self_attn.q_proj", "self_attn.k_proj", "self_attn.v_proj"],
    "self_attn.qkv_proj",
    operations=[Concatenate(dim=0)],
)

MergeModulelist

MergeModulelist menggabungkan daftar tensor 2D menjadi satu tensor 3D. Sebagai contoh, Anda dapat mengomposisikan MergeModulelist dengan Concatenate untuk menumpuk para ahli dalam MoE dan mengemasnya ke dalam satu tensor.

WeightConverter(
    ["block_sparse_moe.experts.*.w1.weight", "block_sparse_moe.experts.*.w3.weight"],
    "mlp.experts.gate_up_proj",
    operations=[MergeModulelist(dim=0), Concatenate(dim=1)],
)

SplitModulelist

SplitModulelist memecah tensor 3D kembali menjadi daftar tensor 2D. Misalnya, Anda dapat memecah tumpukan pakar menjadi pakar-pakar individual.

WeightConverter(
    "mlp.experts.down_proj",
    "block_sparse_moe.experts.*.w2.weight",
    operations=[SplitModulelist(dim=0)],
)

PermuteForRope

PermuteForRope mengonversi bobot dari format terinterleaved ke format sin/cos. Sebagai contoh, Anda dapat menggabungkan Chunk dengan PermuteForRope untuk memisahkan tensor QKV yang terfusi dan menerapkan permutasi RoPE sin/cos ke Q dan K.

WeightConverter(
    ["model.layers.*.self_attn.qkv_proj.weight"],
    [
        "model.layers.*.self_attn.q_proj.weight",
        "model.layers.*.self_attn.k_proj.weight",
        "model.layers.*.self_attn.v_proj.weight",
    ],
    operations=[Chunk(dim=0), PermuteForRope()],
)

Transpose

Transpose menukar dimensi sebuah tensor. Berguna untuk mengonversi tata letak bobot antar konvensi yang berbeda.

WeightConverter(
    source_patterns="mlp.gate.weight",
    target_patterns="mlp.text_moe.gate.weight",
    operations=[Transpose(dim0=0, dim1=1)],
)

Rantai operasi

Operasi dapat dirangkai untuk melakukan transformasi kompleks. Operasi dieksekusi secara berurutan, dengan output dari setiap operasi menjadi input untuk operasi berikutnya.

Contoh: Konversi Mixtral MoE

WeightConverter(
    source_patterns=[
        ".experts.*.w1.weight",  # gate_proj per expert
        ".experts.*.w3.weight",  # up_proj per expert
    ],
    target_patterns=".experts.gate_up_proj",
    operations=[
        MergeModulelist(dim=0),  # Stack all experts: (n_experts, in, out)
        Concatenate(dim=1),      # Fuse gate+up: (n_experts, in, 2*out)
    ],
)

Alur data:

Input:
  ".experts.*.w1.weight": [tensor_0, tensor_1, ..., tensor_7]  # 8 experts
  ".experts.*.w3.weight": [tensor_0, tensor_1, ..., tensor_7]  # 8 experts

After MergeModulelist(dim=0):
  ".experts.*.w1.weight": (8, 4096, 14336)  # stacked gate
  ".experts.*.w3.weight": (8, 4096, 14336)  # stacked up

After Concatenate(dim=1):
  ".experts.gate_up_proj": (8, 4096, 28672)  # fused gate_up

Aturan pencocokan pola

  • Pola sumber adalah regex penuh yang dievaluasi dengan re.search(). ^ mengikat ke awal kunci scoped (setelah penghapusan scope_prefix).
  • * adalah wildcard per-indeks yang mengumpulkan semua tensor yang cocok di bawah pola sumber yang sama (menjaga urutan checkpoint untuk penggabungan yang benar).
  • Grup yang ditangkap dalam pola sumber dapat dirujuk sebagai \1, \2, … dalam pola target untuk mempertahankan bagian dari kunci asli (misalnya, indeks layer).
  • Transform berscope (scope_prefix diset) hanya mencocokkan kunci yang diawali dengan f"{scope_prefix}.".

Mendaftarkan pemetaan konversi

Daftar konversi didaftarkan terhadap kunci string — baik berupa model_type (misalnya "mixtral") maupun nama kelas (misalnya "LlavaModel"):

from transformers.conversion_mapping import register_checkpoint_conversion_mapping

register_checkpoint_conversion_mapping(
    "my_model_type",
    [
        WeightRenaming(".old.", ".new."),
        WeightConverter(
            ".experts.*.w1.weight",
            ".experts.gate_proj",
            operations=[MergeModulelist(dim=0)],
        ),
    ],
)

Aturan pencarian

Ketika get_model_conversion_mapping memproses PreTrainedModel, setiap sub-PreTrainedModel dikunjungi dalam urutan DFS (nn.Module.named_modules() yang difilter menjadi instance PreTrainedModel). Setiap sub-model diselesaikan dalam dua tahap, filter kode kustom dijalankan terlebih dahulu, kemudian pemetaan yang terdaftar dicari.

Model dengan kode kustom dilewati sebelum pencarian apa pun dilakukan. Sub-model dianggap sebagai kode kustom ketika is_custom_code() mengembalikan True, yang mencakup model yang dimuat dari Hub dengan trust_remote_code=True serta kelas model apa pun yang tidak ada di Transformers. Model kode kustom tidak mewarisi pemetaan konversi karena nama kelas atau model_type-nya mungkin bertabrakan dengan model native. Sebagai contoh, arsitektur kustom yang mengatur model_type="mixtral" tidak akan mengambil transformasi expert-fusion bawaan Mixtral.

Daftarkan model kode kustom secara eksplisit dengan register_checkpoint_conversion_mapping untuk menerapkan pemetaan konversi. Pendaftaran menambahkan nama kelas atau model_type ke dalam himpunan pemetaan yang didaftarkan pengguna, yang membebaskan model dari lewati kode kustom dan mengarahkannya melalui pencarian normal di bawah.

Untuk setiap sub-model yang lolos filter kode kustom:

  1. Pencarian berdasarkan nama kelas dicoba terlebih dahulu, kemudian model_type. Jika keduanya terdaftar untuk modul yang sama, pemetaan nama kelas yang menang dan model_type diabaikan untuk modul tersebut — hal ini memungkinkan task head (misalnya LlavaForConditionalGeneration) untuk menimpa baseline model_type bersama ("llava").
  2. Pemetaan yang dipilih memiliki scope_prefix yang disetel ke jalur titik sub-modul ("" untuk root).
  3. Ancestor-based deduplication menentukan apakah pemetaan akan dipertahankan:
    • Jika jalur ancestor sudah mengklaim identifier yang sama (nama kelas atau model_type), sub-modul tersebut akan dilewati — pemetaan tanpa scope atau dengan scope yang lebih tinggi dari ancestor sudah mencakup subtree ini.
    • Jika hanya ada satu sibling yang mengklaimnya, sub-modul akan dipertahankan dengan scope_prefix miliknya sendiri. Setiap sibling mendapatkan pemetaan ber-scope miliknya sendiri.

Daftar yang telah dilihat untuk nama kelas dan model_type dilacak secara terpisah, dengan satu hal yang perlu diperhatikan: ketika sebuah modul dicocokkan melalui nama kelasnya, model_type-nya tidak ditambahkan ke daftar yang telah dilihat. Hal ini dilakukan agar modul lain yang berbagi model_type yang sama tetapi tidak memiliki pemetaan khusus kelas (misalnya DetrModel di bawah DetrForSegmentation) tetap dapat dijangkau melalui pencarian model_type.

Pemetaan berbasis kelas vs alias model_type

Kedua gaya tersebut coexist dalam _MODEL_TO_CONVERSION_PATTERN:

_MODEL_TO_CONVERSION_PATTERN = {
    # model_type aliases (lookup by config.model_type)
    "minimax": "mixtral",
    "qwen3_moe": "qwen2_moe",
    "mistral3": "llava",
    # class-name aliases (lookup by type(submodule).__name__)
    "PaliGemmaModel": "LlavaModel",
    "MaskFormerDetrDecoder": "DetrModel",
    ...
}

Kunci nama kelas lebih disarankan ketika model_type dibagikan tetapi kelas tertentu memerlukan perilaku yang berbeda.

Integrasi paralelisme tensor

Sistem pemuatan dinamis terintegrasi dengan paralelisme tensor (TP) melalui hierarki TensorParallelLayer yang didefinisikan di src/transformers/integrations/tensor_parallel.py.

Ketika TP diaktifkan, tensor dipecah selama materialisasi, bukan setelahnya. Ini berarti setiap rank hanya memuat bagian tensor yang dibutuhkannya.

def spawn_tp_materialize(thread_pool, tensor, sharding_method, tensor_idx, device, dtype):
    def _job():
        return sharding_method.shard_tensor(tensor, tensor_idx=tensor_idx, device=device, dtype=dtype)
    return thread_pool.submit(_job)

Gaya paralel yang tersedia

GayaDimensi Shard BobotDeskripsi
colwise-2Secara kolom: fitur output di-shard
rowwise-1Per baris: fitur input di-shard
packed_colwise-2Untuk bobot yang digabungkan (gate_up_proj)
packed_rowwise-1Untuk bobot yang digabungkan
embedding_rowwise0Paralelisme kosakata
grouped_gemm0Paralelisme pakar untuk MoE
sequence_parallelNoneTidak ada pembagian bobot

Penanganan bobot terpadat

Untuk bobot yang digabungkan seperti gate_up_proj, perhatian khusus diperlukan untuk melakukan sharding dengan benar:

def get_packed_weights(param, empty_param, device_mesh, rank, dim):
    """
    Interleaves gate and up shards correctly.

    Packed tensor: [G0 G1 G2 G3 | U0 U1 U2 U3]

    With TP=2:
    - Rank 0 gets: [G0 G1 | U0 U1]
    - Rank 1 gets: [G2 G3 | U2 U3]
    """

Operasi TP disimpan dalam WeightTransform dan diterapkan setelah operasi konversi:

if matched_tp_pattern := tp_plan_alt.search(renamed_key):
    tp_layer = ALL_PARALLEL_STYLES[model.tp_plan[matched_tp_pattern]]
    mapping.distributed_operation = tp_layer(
        device_mesh=device_mesh,
        rank=device_mesh.get_local_rank(),
        empty_param=empty_param.clone()
    )

Integrasi kuantisasi

Quantisasi terintegrasi ke dalam pipeline pemuatan dengan dua cara, tergantung pada apakah checkpoint sudah dikuantisasi:

  • Checkpoint terkuantisasi: Kuantizer menyediakan instance WeightConverter (melalui get_weight_conversions()) untuk mendeserialisasi tensor terkuantisasi. Dtype checkpoint dipertahankan untuk menghindari cast yang tidak diinginkan.
  • Kuantisasi on-the-fly: Kuantizer menyediakan operasi kuantisasi yang diterapkan setelah operasi konversi, sehingga bobot dikuantisasi saat dimuat.

Quantizer juga dapat menulis ulang seluruh daftar konversi di akhir get_model_conversion_mapping melalui update_weight_conversions(...) — misalnya, dequantizer FP8 menambahkan op Fp8Dequantize di depan setiap konverter yang sudah ada sehingga skala per-blok diterapkan sebelum op expert-merge / concat meratakan struktur per-expert.

Memuat model yang cepat dan efisien

Memuat model menjadi lebih cepat dan menggunakan lebih sedikit memori karena loader mengetahui tensor mana yang diperlukan untuk operasi dan menjadwalkan materialisasinya secara *lazy*.

Loader memindai checkpoint sekali untuk menemukan kecocokan pola dan mengumpulkan tensor. Tensor tersebut disimpan sebagai objek Future dan dikirim ke thread pool untuk dimuat secara asinkron tanpa memblokir GIL. Sebuah parameter mulai dimuat begitu ada thread yang tersedia untuknya.

Jika sistem Anda menjalankan proses berat lainnya, beberapa thread mungkin justru memperlambat proses pemuatan alih-alih mempercepatnya. Dalam kasus ini, atur variabel lingkungan HF_DEACTIVATE_ASYNC_LOAD=1 untuk memuat bobot secara berurutan.

Nilai defaultnya adalah 4 thread untuk pemuatan parameter asinkron. Ini memberikan keseimbangan terbaik di antara berbagai skenario pemuatan dan perangkat keras. Pekerjaan ini sebagian besar terikat pada I/O, tetapi tergantung pada perangkat keras akselerator dan dtype yang diperlukan saat pemuatan, proses ini dapat menjadi terikat pada CPU/GPU jika dtype berbeda dari yang terserialisasi (hal ini memerlukan operasi salinan tambahan).

Pemuatan asinkron vs sinkron

def spawn_materialize(thread_pool, tensor, device, dtype) -> Future | Callable:
    def _job():
        return _materialize_copy(tensor, device, dtype)

    if thread_pool is not None:
        return thread_pool.submit(_job)  # Async: returns Future
    else:
        return _job  # Sync: returns Callable (deferred execution)

Sync loading digunakan ketika:

  • variabel lingkungan HF_DEACTIVATE_ASYNC_LOAD=1 telah disetel.
  • Disk offloading diaktifkan (keterbatasan memori memerlukan pemuatan berurutan).
  • Kuantisasi on-the-fly diaktifkan (menghindari thread pekerja yang melampaui langkah kuantisasi).

Alur materialisasi

1. Checkpoint iteration (Phase 1):
   - For each key, walk the transform list once
   - Submit materialization job to ThreadPoolExecutor
   - Job returns Future (async) or Callable (sync)
   - Collect into the matching WeightConverter / WeightRenaming

2. Per-mapping processing (Phase 2, one mapping at a time):
   - materialize_tensors() waits for this mapping's Futures only
   - Apply conversion operations chain (self.operations)
   - Apply quantization operation (if on-the-fly)
   - Set parameters on model
   - Delete realized tensors immediately

3. Cleanup:
   - Thread pool shutdown (with cancel_futures=True for interrupts)

Efisiensi memori

Saat mengonversi bobot, konverter menunggu hingga semua tensor yang diperlukan terealisasi jika belum dimuat. Sebagai contoh, operasi MergeModulelist membutuhkan semua bobot di ModuleList untuk dimuat sebelum penggabungan dilakukan.

Mengonkatenasi tensor memerlukan salinan sementara, sehingga operasi seperti MergeModulelist dan Concatenate membutuhkan 2x memori dari tensor yang mendasarinya selama konversi. Setelah digabungkan, hanya tensor hasil yang tetap berada di memori. Puncak memori terburuk secara teoretis adalah ukuran model ditambah tensor yang diperlukan untuk operasi MergeModulelist atau Concatenate terbesar.

Kasus terburuk ini hanya terjadi ketika semua parameter lain telah dimuat sebelum konversi yang membutuhkan sumber daya besar dijalankan. Dua skenario memicu hal ini.

  1. Semua parameter dimuat secara asinkron sebelum masuk ke proses konversi yang berat (thread pool lebih cepat daripada antrean konversi).
  2. Konversi yang paling menantang adalah yang terakhir.

Sebagai contoh, model MoE yang menggunakan MergeModulelist untuk para ahli pada setiap lapisan, puncak memori terburuk secara teoretis adalah ukuran model ditambah para ahli pada satu lapisan.

Skenario terburuk ini jarang terjadi. Puncak memori aktual cenderung tetap mendekati ukuran model.

Reversibilitas

Sistem ini mendukung penyimpanan model dengan transformasi invers, sehingga memungkinkan proses simpan/muat bolak-balik. Penyimpanan berjalan dalam dua fase: konverter terbalik terlebih dahulu (setiap tensor cocok dengan paling banyak satu), kemudian penamaan ulang terbalik, sesuai aturan urutan di atas.

def revert_weight_conversion(model, state_dict):
    """Applies reverse conversions for saving."""
    weight_conversions = getattr(model, "_weight_conversions", None)

    # Reverse all transforms
    reverse_weight_conversion = [
        conversion.reverse_transform() for conversion in weight_conversions
    ]

    # Apply in reverse
    for first_param_name, reversed_converter in conversion_mapping.items():
        realized_value = reversed_converter.convert(first_param_name, model=model)

Daftar transformasi yang digunakan saat pemuatan di-cache pada model sebagai _weight_conversions (hanya entri yang benar-benar dipicu yang disimpan, sehingga penamaan ulang non-bijektif seperti PrefixChange diterapkan secara simetris dengan benar). Ketika model diinstansiasi tanpa from_pretrained (dan karenanya tidak memiliki _weight_conversions), revert_weight_conversion kembali ke perhitungan ulang pemetaan melalui get_model_conversion_mapping dan membuang semua PrefixChange darinya (kita tidak dapat mengetahui apakah checkpoint asli memiliki prefiks tersebut).

Pola target dapat berisi elemen regex yang perlu diproses untuk arah sebaliknya:

def process_target_pattern(pattern: str) -> tuple[str, str | None]:
    """
    - Removes `^` and `$` anchors
    - Removes negative lookahead/lookbehind
    - Detects capturing groups, replaces with \1
    """

Contoh nyata

MoE bergaya Mixtral

Format checkpoint:

model.layers.0.block_sparse_moe.experts.0.w1.weight  # gate per expert
model.layers.0.block_sparse_moe.experts.0.w2.weight  # down per expert
model.layers.0.block_sparse_moe.experts.0.w3.weight  # up per expert
...
model.layers.0.block_sparse_moe.experts.7.w1.weight

Format model:

model.layers.0.mlp.experts.gate_up_proj  # (8, 4096, 28672)
model.layers.0.mlp.experts.down_proj     # (8, 14336, 4096)

Pemetaan konversi (dari conversion_mapping.py):

"mixtral": [
    WeightRenaming(".block_sparse_moe.", ".mlp."),
    WeightConverter(
        source_patterns=[".experts.*.w1.weight", ".experts.*.w3.weight"],
        target_patterns=".experts.gate_up_proj",
        operations=[MergeModulelist(dim=0), Concatenate(dim=1)],
    ),
    WeightConverter(
        source_patterns=[".experts.*.w2.weight"],
        target_patterns=".experts.down_proj",
        operations=[MergeModulelist(dim=0)],
    ),
],

Model bahasa-visi komposit (Gemma3)

Gemma3 memiliki pengaturan standar “logika prefiks yang berbeda untuk model head dibandingkan model dasar”. Dua entri didaftarkan (di sini melalui alias yang menunjuk ke daftar "llava" / "LlavaModel" yang dibagikan):

# model_type: applies to Gemma3ForConditionalGeneration / Gemma3ForSequenceClassification
"gemma3": "llava"           # → adds "model." in front of language_model / vision_tower / ...

# class:    applies to the inner Gemma3Model only
"Gemma3Model": "LlavaModel"  # → minimal rename inside the already-prefixed namespace

DFS walk untuk Gemma3ForConditionalGeneration:

  1. Root — pencarian class tidak ditemukan (Gemma3ForConditionalGeneration tidak terdaftar), pencarian model_type ditemukan ("gemma3") → transformasi penulisan ulang prefiks "llava" ditambahkan tanpa scope, sehingga language_model, vision_tower, multi_modal_projector berada di bawah model.*.
  2. Inner model: Gemma3Model — class lookup hits (Gemma3Model → LlavaModel) → hanya pemetaan LlavaModel yang diterapkan, dengan cakupan "model". Penamaan ulang prefix "gemma3" (="llava") yang jauh lebih luas tidak diterapkan ulang di sini, yang memang persis seperti yang Anda inginkan: model inner berada dalam namespace di mana prefix sudah benar.

Bentuk pasangan yang sama digunakan oleh setiap VLM dari keluarga Llava (PaliGemma, InternVL, Mistral3, …). Entri model_type menangani operasi prefix pada model head; entri class menjaga pemetaan model dasar internal tetap minimal.

Penyaringan lebih dalam dengan penimpaan spesifik untuk head (DETR)

DetrForSegmentation menunjukkan override yang spesifik untuk head, yang ditumpangkan di atas dua tingkat bersarang:

DetrForSegmentation                  (class registered: segmentation-only renames)
├── detr: DetrForObjectDetection     (no mapping; just walked through)
│   └── model: DetrModel             (class registered: shared base transforms)
│       └── backbone, encoder, ...
└── mask_head, bbox_attention        (head-specific weights)

Dua pemetaan terlibat (satu untuk setiap kunci yang terdaftar):

"DetrModel":           [WeightRenaming("backbone.conv_encoder", "backbone"), ...]      # shared base
"DetrForSegmentation": [WeightRenaming("mask_head.lay1", "mask_head.conv1.conv"), ...] # head-specific

Jalan DFS:

  1. Root DetrForSegmentation cocok berdasarkan kelas → penamaan ulang segmentasi ditambahkan unscoped.
  2. detr: DetrForObjectDetection tidak terdaftar → tidak ada transformasi yang ditambahkan; DFS terus masuk ke dalamnya.
  3. detr.model: DetrModel cocok berdasarkan kelas → transformasi dasar ditambahkan dengan scope_prefix="detr.model".

Inilah mengapa DetrForObjectDetection tidak memerlukan pemetaan tersendiri: satu-satunya pemetaan yang terdaftar di subpohonnya (DetrModel) secara otomatis di-cakupan ke jalur yang tepat.

Alias berbasis kelas (class-keyed aliases) menggunakan pemetaan dasar tanpa perlu registrasi tambahan: "MaskFormerDetrDecoder": "DetrModel" membuat decoder MaskFormer mengambil transformasi yang sama di bawah nama kelasnya sendiri.

Operasi kustom (ERNIE 4.5 VL MoE)

Ketika operasi bawaan tidak memadai, Anda dapat membuat subclass ConversionOps kustom. Misalnya, ERNIE 4.5 VL MoE perlu memisahkan daftar expert bersama antara modalitas teks dan visual — sesuatu yang tidak ditangani oleh satu pun operasi bawaan. Operasi kustom ErnieFuseAndSplitTextVisionExperts memisahkan dan menumpuk ulang expert di antara dua kunci target:

"ernie4_5_vl_moe": [
    WeightRenaming("vision_model", "vision_tower"),
    WeightConverter(
        source_patterns=["experts.*.down_proj.weight"],
        target_patterns=[
            "text_moe.experts.down_proj",
            "vision_moe.experts.down_proj",
        ],
        operations=[ErnieFuseAndSplitTextVisionExperts(stack_dim=0, concat_dim=1)],
    ),
],

Custom ops harus mengimplementasikan convert() dan properti reverse_op untuk mendukung round-trip save/load.

Alias tipe model

Banyak model memiliki pola konversi yang sama:

_MODEL_TO_CONVERSION_PATTERN = {
    "mixtral": "mixtral",
    "minimax": "mixtral",
    "qwen2_moe": "qwen2_moe",
    "deepseek_v2": "qwen2_moe",
    "deepseek_v3": "qwen2_moe",
    "qwen3_moe": "qwen2_moe",
    "olmoe": "qwen2_moe",
    ...
}

Memanfaatkan kembali komponen dasar pemuatan dinamis

Pemuatan bobot dinamis tidak terbatas pada checkpoint model lengkap. Komponen pembangun yang sama memungkinkan Anda memuat setiap kumpulan bobot, selama Anda dapat mendeskripsikan bagaimana kunci checkpoint dipetakan ke parameter dan memastikan modul target ada.

Secara garis besar, kontraknya terlihat seperti ini:

  1. Siapkan namespace model. Pastikan modul/parameter yang ingin dimuat sudah ada dan diberi nama sesuai dengan target pemetaan Anda. Untuk adapter, hal ini berarti memanggil inject_adapter_in_model(...) agar modul adapter ada sebelum dimuat. Untuk head kustom atau modul tambahan, instansiasikan terlebih dahulu pada model.
  2. Describe how to map weights. Buat daftar konversi/penamaan ulang (misalnya, di dalam helper seperti _build_peft_weight_mapping(...)) menggunakan WeightConverter atau WeightRenaming. Di sinilah Anda menyatakan bagaimana kunci checkpoint harus dikonversi, dipecah, digabungkan, atau dinamai ulang agar sesuai dengan namespace model Anda. Anda dapat melakukan tiga hal utama:
    • tambahkan operasi ke daftar konverter: operasi ini akan diterapkan pada semua bobot, kecuali bobot yang dikumpulkan di salah satu WeightConverter. Secara umum, operasi ini seharusnya berupa operasi WeightRenaming
    • tambahkan operasi ke daftar operasi dari setiap converter: inilah yang terjadi untuk Quantization, di mana kami hanya menambahkan operasi kuantisasi setelah daftar operasi dari WeightConverter mana pun.
    • ganti operasi / map ke operasi kustom Anda: inilah yang terjadi dengan peft. Kami mengganti operasi Concatenate dari, misalnya, mixtral, menjadi PeftConcatenate (yang didefinisikan di PEFT). Dengan cara ini, saat checkpoint adapter dibaca, bobot yang akan digabungkan akan dikumpulkan, dan diformat dengan benar untuk peft
  3. Load + finalize + report. Gunakan core loader untuk melakukan konversi dan mengisi tensor, kemudian finalisasi dan catat hasilnya. Secara konkret, alur ini adalah:
    • LoadStateDictConfig(...) + _load_pretrained_model(...) untuk memuat dan mengonversi.
    • _finalize_load_state_dict(...) untuk memindahkan tensor yang hilang/tidak cocok dari meta, menginisialisasinya, dan mengikat bobot.
    • log_state_dict_report(...) untuk melaporkan kunci yang hilang/tidak diharapkan/tidak cocok (dan kesalahan konversi).

API-API ini disediakan agar Anda dapat menangani kode kustom dan format bobot kustom, sekaligus memastikan Anda mendapatkan manfaat dari pemuatan bobot, sharding, dan kenyamanan penggunaan terbaik serta paling efisien dari API transformers!

Referensi file utama

FileTujuan
src/transformers/core_model_loading.pyLogika pemuatan inti, WeightConverter, WeightRenaming, ConversionOps
src/transformers/conversion_mapping.pyPemetaan bawaan dan komposisi per-submodel (get_model_conversion_mapping)
src/transformers/integrations/tensor_parallel.pyKelas dan utilitas sharding TP
src/transformers/quantizers/base.pyHook kuantisasi dan kelas dasar
Update on GitHub