Lompat ke konten
dokumentasi.id
Commit ce728f6
v1
Star659

Kamu membaca versi lama. Halaman ini hanya bisa dibaca.

8

Data Utils dan Dataloader

Modul utils/data_utils.py menyimpan seluruh pasangan kelas Dataset dan DataLoader untuk 12 task downstream dalam satu berkas. Setiap task mendapat satu subkelas torch.utils.data.Dataset yang membaca berkasnya sendiri, lalu satu subkelas DataLoader yang menyetel collate_fn ke metode _collate_fn miliknya. Keduanya dipilih pada saat runtime lewat kunci dataset_class dan dataloader_class di utils/args_helper.py:83-88.

Satu pasang kelas untuk setiap task

Konstanta statis pada setiap kelas Dataset menentukan jumlah label yang akhirnya dipakai untuk menyusun kepala klasifikasi. Tabel berikut memetakan nilai --dataset ke kelasnya.

--datasetKelas DatasetKelas DataLoaderNUM_LABELSRujukan
term-extraction-airyAspectExtractionDatasetAspectExtractionDataLoader5utils/data_utils.py:12-16
ner-gritNerGritDatasetNerDataLoader7utils/data_utils.py:101-105
ner-prosaNerProsaDatasetNerDataLoader11utils/data_utils.py:156-160
pos-idnPosTagIdnDatasetPosTagDataLoader41utils/data_utils.py:245-249
pos-prosaPosTagProsaDatasetPosTagDataLoader26utils/data_utils.py:300-304
emotion-twitterEmotionDetectionDatasetEmotionDetectionDataLoader5utils/data_utils.py:389-393
entailment-uiEntailmentDatasetEntailmentDataLoader2utils/data_utils.py:443-447
doc-sentiment-prosaDocumentSentimentDatasetDocumentSentimentDataLoader3utils/data_utils.py:504-508
keyword-extraction-prosaKeywordExtractionDatasetKeywordExtractionDataLoader3utils/data_utils.py:559-563
qa-factoid-itbQAFactoidDatasetQAFactoidDataLoader3utils/data_utils.py:649-653
absa-airyAspectBasedSentimentAnalysisAiryDatasetAspectBasedSentimentAnalysisDataLoader[4, 4, 4, 4, 4, 4, 4, 4, 4, 4]utils/data_utils.py:744-750
absa-prosaAspectBasedSentimentAnalysisProsaDatasetAspectBasedSentimentAnalysisDataLoader[3, 3, 3, 3, 3, 3]utils/data_utils.py:772-778

Dua task ABSA memakai daftar NUM_LABELS, bukan satu angka, karena setiap aspek punya klasifikasi sendiri: 10 aspek pada data Airy dan 6 aspek pada data Prosa. NUM_ASPECTS menyimpan panjang daftar itu, dan AspectBasedSentimentAnalysisDataLoader membacanya dari dataset.NUM_ASPECTS saat __init__ untuk menentukan lebar label_batch (utils/data_utils.py:801-827).

Nama task di kolom pertama bukan bagian dari modul data; pemetaannya ada di append_dataset_args pada utils/args_helper.py:83-88, dan setiap cabang mengisi dataset_class serta dataloader_class sekaligus. Rincian arti tiap label dibahas di 12 Task Downstream dan Jenis Klasifikasi.

Tokenisasi subword dan pemetaan subword_to_word_indices

Kelas Dataset untuk task token-level memakai pola yang sama. Berkas teks dibaca baris demi baris; baris yang memuat \t dipecah menjadi token dan label, dan baris kosong menutup satu kalimat (utils/data_utils.py:18-38). AspectExtractionDataset memakai penanda if '\t' in line, sedangkan NerGritDataset dan PosTagIdnDataset memakai if len(line.strip()) > 0; keduanya menghasilkan daftar {'sentence': ..., 'seq_label': ...}.

Pada __getitem__, setiap kata di-encode sendiri dengan add_special_tokens=False. Panjang subword_list menentukan berapa kali word_idx diulang ke dalam subword_to_word_indices, sehingga satu kata yang pecah menjadi tiga subword menyumbang tiga entri dengan indeks yang sama (utils/data_utils.py:44-62). cls_token_id disisipkan di depan dan sep_token_id di belakang, dan keduanya diberi penanda -1 karena bukan bagian dari kata mana pun.

graph TD
  raw["berkas .txt: token TAB label"] --> loader["load_dataset"]
  loader --> buf["dataset: list of sentence + seq_label"]
  buf --> enc["tokenizer.encode(word, add_special_tokens=False)"]
  enc --> map["subword_to_word_indices: word_idx per subword"]
  map --> cls["cls_token_id di depan, sep_token_id di belakang"]
  cls --> idx["posisi khusus ditandai -1"]
  idx --> item["np.array(subwords), np.array(subword_to_word_indices), np.array(seq_label), sentence"]
  style raw fill:#336791,color:#fff
  style buf fill:#8b5cf6,color:#fff
  style idx fill:#f59e0b,color:#000
  style item fill:#2d7d46,color:#fff
%% fig: Dari baris berlabel ke satu contoh Dataset
%% desc: load_dataset mengubah berkas teks menjadi daftar kalimat, lalu __getitem__ memecah setiap kata menjadi subword dan mencatat pemetaan subword ke indeks kata.
Fig. 1: Dari baris berlabel ke satu contoh Datasetload_dataset mengubah berkas teks menjadi daftar kalimat, lalu __getitem__ memecah setiap kata menjadi subword dan mencatat pemetaan subword ke indeks kata.

Pemetaan yang sama dipakai tiga kali: oleh NerDataLoader, PosTagDataLoader, dan KeywordExtractionDataLoader. Ketiganya meneruskan subword_to_word_indices_batch sebagai argumen tersendiri ke model (utils/data_utils.py:211-240, utils/data_utils.py:355-384, utils/data_utils.py:614-644).

Untuk model berbasis kata, SimpleTokenizer di utils/functions.py mengambil peran tokenizer Hugging Face. Kelas ini menambah <cls>, <sep>, <pad>, dan beberapa token khusus lain ke vocab pada __init__, lalu menyimpan cls_token_id dan sep_token_id sebagai atribut sehingga __getitem__ di data_utils.py dapat memakainya tanpa perubahan (utils/functions.py:16-37). Metode encode mengembalikan daftar id tanpa token khusus bila add_special_tokens=False, dan menyisipkan <cls> serta <sep> bila tidak (utils/functions.py:48-61). Metode encode_plus menambahkan token_type_ids agar pasangan kalimat dapat dibedakan (utils/functions.py:63-85).

collate_fn: padding, masking, dan nilai penanda

Setiap DataLoader menyetel self.collate_fn = self._collate_fn dan menyimpan max_seq_len dengan nilai default 512. _collate_fn menghitung panjang terpanjang di dalam batch, memotongnya dengan min(self.max_seq_len, max_seq_len), lalu menyiapkan array numpy dengan lebar tersebut (utils/data_utils.py:67-96).

ArraydtypeNilai awalPeran
subword_batchnp.int64np.zerosid subword, sisa posisi tetap 0
mask_batchnp.float32np.zeros, diisi 1 sepanjang token asliattention_mask
subword_to_word_indices_batchnp.int64np.full(..., -1)indeks kata asal per subword
seq_label_batchnp.int64np.full(..., -100)label token-level, posisi padding diabaikan
token_type_batchnp.int64np.zerospenanda segmen A/B pada task pasangan kalimat

Nilai -100 adalah penanda abaikan yang dikenali lintas modul. forward_word_classification berhenti mengiterasi label begitu menemukan -100, sehingga posisi padding tidak masuk perhitungan metrik (utils/forward_fn.py:43-56). Task sekuens dengan satu label per kalimat memakai label_batch berbentuk (batch_size, 1) yang diisi -100 sebelum ditimpa, seperti pada EmotionDetectionDataLoader (utils/data_utils.py:414-438) dan DocumentSentimentDataLoader (utils/data_utils.py:530-554).

graph TD
  batch["batch: list of tuple dari __getitem__"] --> maxlen["max_seq_len = min(self.max_seq_len, max panjang batch)"]
  maxlen --> sub["subword_batch: np.zeros int64"]
  maxlen --> mask["mask_batch: np.zeros float32, diisi 1 untuk token asli"]
  maxlen --> ind["subword_to_word_indices_batch: np.full -1"]
  maxlen --> lab["seq_label_batch: np.full -100"]
  sub --> ret["return 4 sampai 6 numpy array"]
  mask --> ret
  ind --> ret
  lab --> ret
  style maxlen fill:#f59e0b,color:#000
  style sub fill:#8b5cf6,color:#fff
  style ind fill:#8b5cf6,color:#fff
  style lab fill:#8b5cf6,color:#fff
  style ret fill:#2d7d46,color:#fff
%% fig: Penyusunan satu batch di _collate_fn
%% desc: Panjang terpanjang di dalam batch menentukan lebar setiap array, lalu nilai penanda -1 dan -100 diisi pada posisi yang tidak terpakai.
Fig. 2: Penyusunan satu batch di _collate_fnPanjang terpanjang di dalam batch menentukan lebar setiap array, lalu nilai penanda -1 dan -100 diisi pada posisi yang tidak terpakai.

Bentuk tuple yang dikembalikan berbeda antar task, dan main.py tidak pernah membongkarnya sendiri. Loop evaluasi memakai batch_data[-1] sebagai list_seq dan mengirim batch_data[:-1] ke forward_fn, sehingga jumlah elemen di depan bebas berubah asal forward_fn yang dipilih mengetahuinya (main.py:47-50).

Kelas DataLoaderTuple yang dikembalikanRujukan
AspectExtractionDataLoader, NerDataLoader, PosTagDataLoader, KeywordExtractionDataLoadersubword, mask, subword_to_word_indices, seq_label, sequtils/data_utils.py:67-96
EmotionDetectionDataLoader, DocumentSentimentDataLoadersubword, mask, label, sequtils/data_utils.py:414-438
EntailmentDataLoadersubword, mask, token_type, label, sequtils/data_utils.py:472-499
QAFactoidDataLoadersubword, mask, token_type, subword_to_word_indices, seq_label, sequtils/data_utils.py:708-739
AspectBasedSentimentAnalysisDataLoadersubword, mask, label, seq dengan label selebar num_aspectsutils/data_utils.py:801-827

Task yang membandingkan dua kalimat mengisi token_type_batch dari encode_plus. EntailmentDataset memanggil encode_plus(sent_A, sent_B, add_special_tokens=not self.no_special_token, return_token_type_ids=True) lalu mengembalikan subwords, token_type_ids, label, dan gabungan sent_A + "|" + sent_B (utils/data_utils.py:459-466). QAFactoidDataset membangun token_type_ids secara manual: 0 untuk question beserta cls_token_id dan sep_token_id perantara, 1 untuk passage dan sep_token_id penutup. Semua subword dari question diberi subword_to_word_indices -1 karena label hanya dipasang pada passage (utils/data_utils.py:670-703).

Alur dari konfigurasi ke forward_fn

main.py membuat tiga pasang dataset dan loader, satu untuk train, valid, dan test, dengan num_workers=16 dan shuffle=False pada ketiganya. Argumen max_seq_len, batch_size, dan no_special_token diteruskan langsung dari args (main.py:172-182). Baris yang sama juga dipakai predict.py saat menyiapkan test_loader untuk inferensi (predict.py:94-95).

graph LR
  args["args dataset_class dan dataloader_class"] --> ds["Dataset(dataset_path, tokenizer, lowercase, no_special_token)"]
  ds --> dl["DataLoader(dataset, max_seq_len, batch_size, num_workers=16, shuffle=False)"]
  dl --> loop["evaluate: for batch_data in data_loader"]
  loop --> fw["forward_fn(model, batch_data[:-1], i2w=i2w)"]
  loop --> seq["batch_data[-1] masuk list_seq"]
  style args fill:#f59e0b,color:#000
  style ds fill:#8b5cf6,color:#fff
  style dl fill:#336791,color:#fff
  style fw fill:#2d7d46,color:#fff
%% fig: Dataset, DataLoader, dan pemakaiannya di main.py
%% desc: Kelas yang dipilih lewat args menghasilkan dataset dan loader, lalu setiap batch dibongkar menjadi input model dan deret teks asli.
Fig. 3: Dataset, DataLoader, dan pemakaiannya di main.pyKelas yang dipilih lewat args menghasilkan dataset dan loader, lalu setiap batch dibongkar menjadi input model dan deret teks asli.

Versi awal di notebook

Empat notebook di data_utils_notebook/ memuat versi kelas-kelas ini sebelum dipindahkan ke modul. Bedanya terlihat pada penanganan token khusus. Di data_utils_notebook/postag_data_utils.ipynb:22-71, setiap kata di-encode dengan add_special_tokens=True dan subword_to_word_indices dibangun mulai dari 0 tanpa entri -1, sehingga tidak ada posisi khusus di awal maupun akhir. Notebook tersebut juga belum menyiapkan mask_batch; _collate_fn hanya mengembalikan subword_batch, subword_to_word_indices_batch, dan seq_label_batch (data_utils_notebook/postag_data_utils.ipynb:80-89). Ketiga notebook lain mengikuti pola yang sama untuk task masing-masing (data_utils_notebook/ner_data_utils.ipynb:22-89, data_utils_notebook/aspect_extraction_data_util.ipynb:22-89, data_utils_notebook/aspect_based_sentiment_analysis.ipynb:22-71).

⚠️ NewsCategorizationDataLoader tidak dapat dijalankan apa adanya. _collate_fn memakai NUM_LABELS sebagai nama lepas padahal konstanta itu hanya ada sebagai atribut kelas NewsCategorizationDataset, loop-nya membongkar dua nilai (subwords, labels) sementara seq_list.append(raw_seq) menyebut variabel yang tidak pernah didefinisikan, dan tidak ada cabang news-category-prosa di append_dataset_args. Rujuk utils/data_utils.py:858-887 dan bandingkan dengan pemetaan task di utils/args_helper.py:83-88; append_dataset_args hanya melempar ValueError(f'Unknown dataset name ...') untuk nama yang tidak dikenal.

Muara seluruh tensor ini, termasuk cara forward_fn mengubahnya menjadi list_hyp dan list_label, dibahas di Forward Pass dan Metrik Evaluasi. Urutan pemanggilan loader di dalam train dan evaluate dibahas di Alur Training dan Evaluasi, sedangkan asal nilai max_seq_len dan batch_size ada di Konfigurasi Argumen dan Pemilihan Model.