10
Modul Kepala Klasifikasi
Direktori modules/ berisi tepat dua berkas, word_classification.py dan multi_label_classification.py, tanpa __init__.py. Keduanya diimpor lewat jalur modul penuh di utils/functions.py, yaitu from modules.word_classification import ... dan from modules.multi_label_classification import ... (utils/functions.py:6-71). Setiap berkas mendefinisikan empat kepala klasifikasi di atas encoder transformer: satu untuk BERT, ALBERT, XLM, dan XLM-Roberta. Jumlah label dibaca dari config.num_labels pada varian word classification (modules/word_classification.py:35-442) dan dari config.num_labels_list pada varian multi-label (modules/multi_label_classification.py:34-433).
Peta base model ke kelas prediksi
Pemilihan kelas tidak terjadi di dalam modules/, melainkan di get_model_class. Fungsi itu mencocokkan substring model_type untuk menentukan base_cls, lalu mencocokkan nilai task untuk menentukan pred_cls (utils/functions.py:145-1784). Jenis task itu sendiri dijelaskan di 12 Task Downstream dan Jenis Klasifikasi.
graph TD
GM["get_model_class(model_type, task)"]
GM -->|"'babert-lite'"| AB["base_cls = AlbertModel"]
GM -->|"'xlm-mlm'"| XB["base_cls = XLMModel"]
GM -->|"'xlm-roberta'"| RB["base_cls = XLMRobertaModel"]
GM -->|"lainnya"| BB["base_cls = BertModel"]
AB --> AW["AlbertForWordClassification"]
AB --> AM["AlbertForMultiLabelClassification"]
XB --> XW["XLMForWordClassification"]
XB --> XM["XLMForMultiLabelClassification"]
RB --> RW["XLMRobertaForWordClassification"]
RB --> RM["XLMRobertaForMultiLabelClassification"]
BB --> BW["BertForWordClassification"]
BB --> BM["BertForMultiLabelClassification"]
style GM fill:#f59e0b,color:#000
style AB fill:#336791,color:#fff
style XB fill:#336791,color:#fff
style RB fill:#336791,color:#fff
style BB fill:#336791,color:#fff
style AW fill:#2d7d46,color:#fff
style XW fill:#2d7d46,color:#fff
style RW fill:#2d7d46,color:#fff
style BW fill:#2d7d46,color:#fff
style AM fill:#8b5cf6,color:#fff
style XM fill:#8b5cf6,color:#fff
style RM fill:#8b5cf6,color:#fff
style BM fill:#8b5cf6,color:#fff
%% fig: Pemetaan model_type dan task ke kelas kepala
%% desc: get_model_class memilih base_cls dari substring model_type, lalu memilih kepala word classification atau multi-label dari nilai task.Varian model_type | base_cls | task = token_classification | task = multi_label_classification |
|---|---|---|---|
'babert-lite' | AlbertModel | AlbertForWordClassification | AlbertForMultiLabelClassification |
'xlm-mlm' | XLMModel | XLMForWordClassification | XLMForMultiLabelClassification |
'xlm-roberta' | XLMRobertaModel | XLMRobertaForWordClassification | XLMRobertaForMultiLabelClassification |
'babert', 'bert-base-multilingual', 'word2vec', 'fasttext', 'scratch' | BertModel | BertForWordClassification | BertForMultiLabelClassification |
Cabang terakhir diambil untuk semua model_type yang tidak cocok dengan tiga pola sebelumnya, sesuai komentar pada blok else (utils/functions.py:145-1784). Argumen yang mengisi model_type dan task dibahas di Konfigurasi Argumen dan Pemilihan Model.
Kepala word classification: rata-rata per kata
Keempat kelas word classification menerima subword_to_word_ids sebagai argumen forward. Setelah encoder dijalankan, tiap posisi kata i dihitung dari rata-rata representasi subword yang memakai id tersebut. Hasilnya ditumpuk menjadi word_batch, di-dropout, lalu dilewatkan ke self.classifier (modules/word_classification.py:90-1075).
graph LR
ENC["outputs[0]: sequence_output"] --> MASK["mask = (subword_to_word_ids == i).unsqueeze(-1)"]
MASK --> LAT["word_latents: (sequence_output * mask).sum(dim=1) / mask.sum()"]
LAT --> STK["torch.stack(word_latents, dim=1)"]
STK --> DR["self.dropout"]
DR --> LIN["self.classifier: Linear(hidden_size, num_labels)"]
LIN --> LOG["logits"]
LOG --> LOSS["CrossEntropyLoss(logits.view(-1, num_labels), labels.view(-1))"]
style ENC fill:#336791,color:#fff
style LAT fill:#8b5cf6,color:#fff
style LOG fill:#8b5cf6,color:#fff
style LOSS fill:#2d7d46,color:#fff
%% fig: Alur kepala word classification
%% desc: Representasi subword dirata-ratakan per kata, di-dropout, diklasifikasikan per kata, lalu loss dihitung bila labels tersedia.Bentuk __init__ keempat kelas hampir identik: self.num_labels = config.num_labels, satu nn.Dropout, dan satu nn.Linear(config.hidden_size, config.num_labels) (modules/word_classification.py:38-426). Perbedaan yang tersisa ada pada nama atribut encoder dan sumber probabilitas dropout. BertForWordClassification memakai config.hidden_dropout_prob (modules/word_classification.py:35-442), AlbertForWordClassification juga memakai config.hidden_dropout_prob (modules/word_classification.py:111-120), sedangkan XLMForWordClassification memakai config.dropout (modules/word_classification.py:165-169). XLMRobertaForWordClassification memakai config.hidden_dropout_prob dengan atribut encoder bernama self.roberta (modules/word_classification.py:250-254).
Signature forward juga tidak seragam. Varian BERT dan XLM-Roberta menerima inputs_embeds, sedangkan varian ALBERT dan XLM tidak (modules/word_classification.py:46-5610, modules/word_classification.py:122-13211). Varian XLM meneruskan langs ke self.transformer (modules/word_classification.py:213-22012).
Kepala multi-label: satu linear per kolom label
Pada varian multi-label, self.num_labels bukan bilangan bulat melainkan list config.num_labels_list, dan self.classifiers berupa nn.ModuleList dengan satu nn.Linear(config.hidden_size, num_label) untuk setiap entri list itu (modules/multi_label_classification.py:34-433). Panjang list menentukan berapa kolom label yang diprediksi sekaligus, misalnya config.num_labels_list = [2,3,4,5,6,7] pada blok uji XLMRobertaForMultiLabelClassification (modules/multi_label_classification.py:380-38613).
graph LR
B1["BertModel / AlbertModel: self.dropout(outputs[1])"] --> H0["classifiers[0]: Linear(hidden_size, num_labels_list[0])"]
B2["XLMModel / XLMRobertaModel: self.dropout(self.pooler(outputs[0][:,0,:]))"] --> H0
B1 --> HN["classifiers[n]: Linear(hidden_size, num_labels_list[n])"]
B2 --> HN
H0 --> LG["logits (list)"]
HN --> LG
LG --> TL["total_loss: penjumlahan CrossEntropyLoss per kolom label"]
style B1 fill:#336791,color:#fff
style B2 fill:#336791,color:#fff
style H0 fill:#8b5cf6,color:#fff
style HN fill:#8b5cf6,color:#fff
style TL fill:#2d7d46,color:#fff
%% fig: Percabangan kepala multi-label
%% desc: Vektor ringkas encoder masuk ke satu linear per kolom label, lalu loss tiap kolom dijumlahkan menjadi total_loss.Representasi masukan kepala berbeda antar base model. BertForMultiLabelClassification dan AlbertForMultiLabelClassification memakai outputs[1] setelah dropout (modules/multi_label_classification.py:89-9314, modules/multi_label_classification.py:162-16615). XLMForMultiLabelClassification dan XLMRobertaForMultiLabelClassification menambahkan self.pooler = nn.Sequential(nn.Linear(config.hidden_size, config.hidden_size), nn.Tanh()) dan memakai token pertama outputs[0][:,0,:] (modules/multi_label_classification.py:242-24616, modules/multi_label_classification.py:334-33817).
Loss dihitung dengan CrossEntropyLoss. total_loss diinisialisasi 0, lalu ditambah loss setiap kolom label di dalam loop zip(logits, self.num_labels), sehingga outputs menjadi (total_loss, logits, ...) (modules/multi_label_classification.py:96-10318). Varian XLM dan XLM-Roberta menjalankan pola yang sama (modules/multi_label_classification.py:249-25619).
Kunci config yang dibaca kepala
| Kunci config | Tipe | Dibaca oleh |
|---|---|---|
num_labels | int | self.num_labels dan nn.Linear(config.hidden_size, config.num_labels) di kelas word classification |
num_labels_list | list int | self.num_labels dan panjang nn.ModuleList di kelas multi-label |
hidden_size | int | dimensi masukan classifier maupun classifiers |
hidden_dropout_prob | float | nn.Dropout di kelas BERT, ALBERT, dan XLM-Roberta |
dropout | float | nn.Dropout di kelas XLM |
Nilai num_labels dan num_labels_list diisi pemanggil sebelum model dibuat. Ketika num_labels berbentuk list, pemanggil menulis config.num_labels = max(num_labels) sekaligus config.num_labels_list = num_labels (utils/functions.py:262-26620). Pola yang sama dipakai saat model diinstansiasi dari embedding word2vec atau fasttext (utils/functions.py:192-19821).
Memasang base model terlatih ke kepala
load_eval_model membuat kepala lebih dulu dengan pred_cls(config=config), lalu memuat bobot encoder memakai base_cls.from_pretrained(model_path, from_tf=False, config=config). Bobot itu dipasang dengan mengganti atribut yang namanya cocok: bert, albert, roberta, atau transformer. Bila tidak ada yang cocok, fungsi tidak melempar error, hanya membuat objek ValueError tanpa me-raise (utils/functions.py:260-28222).
Nama atribut itu harus konsisten dengan base_model_prefix. XLMRobertaForWordClassification menyetel config_class = XLMRobertaConfig, pretrained_model_archive_map = XLM_ROBERTA_PRETRAINED_MODEL_ARCHIVE_MAP, dan base_model_prefix = "roberta" (modules/word_classification.py:243-24623).
Jebakan yang perlu diketahui
⚠️
XLMRobertaForWordClassificationmewarisiBertPreTrainedModel, bukan kelas XLM-Roberta, lalu menimpaconfig_classdanpretrained_model_archive_mapsecara manual (modules/word_classification.py:243-24623).base_model_prefixyang benar tetap wajib agar bobotroberta.*termuat.
⚠️ Argumen
token_type_idsdikomentari pada pemanggilan encoder diXLMRobertaForWordClassification(modules/word_classification.py:306-31324), tetapi tetap dikirim padaXLMRobertaForMultiLabelClassification(modules/multi_label_classification.py:325-33225). Dua kepala dengan base model sama meneruskan argumen berbeda.
⚠️ Normalisasi rata-rata kata memakai
mask.sum()yang bernilai skalar untuk seluruh batch, bukan jumlah subword per contoh (modules/word_classification.py:92-9826). Nilaiword_latentskarena itu bukan rata-rata per kata yang ternormalisasi penuh.
⚠️
AlbertForMultiLabelClassificationmenghitung loss denganloss_fct(logit, label.view(-1))tanpa meratakanlogitlebih dulu (modules/multi_label_classification.py:169-17627), sedangkanBertForMultiLabelClassificationmemakailogit.view(-1, num_label)(modules/multi_label_classification.py:99-10228).
⚠️
MSELossdiimpor di kedua berkas tetapi tidak dipakai di mana pun (modules/word_classification.py:729, modules/multi_label_classification.py:730).
Uji cepat di akhir berkas
Kedua berkas ditutup dengan blok if __name__ == '__main__' yang menginstansiasi keempat kelas memakai checkpoint contoh: bert-base-uncased, albert-base-v2, xlm-mlm-100-1280, dan xlm-roberta-base (modules/word_classification.py:337-35631). Blok pada berkas multi-label juga menyetel config.num_labels_list dan menjalankan forward dengan labels untuk mencetak output[0] dan output[1] (modules/multi_label_classification.py:352-38632). Hasil forward itu yang kemudian dipakai metrik evaluasi, seperti dijelaskan di Forward Pass dan Metrik Evaluasi.