Pipeline spaCy adalah barisan komponen yang memproses satu objek Doc secara berurutan, mulai dari representasi numerik token hingga pengenalan entitas bernama. Topik ini membahas arsitektur pipeline en_core_web_sm, penambahan komponen kustom (custom component) melalui @Language.component dan nlp.add_pipe, serta gabungan aturan deterministik dengan model statistik. Setelah membacanya, urutan komponen pada pipeline dapat dibaca, komponen kustom dapat dipasang pada posisi yang benar, dan pembagian kerja antara aturan serta model statistik dapat dijelaskan.
Arsitektur pipeline en_core_web_sm#
Tokenizer memotong teks menjadi token sebelum komponen mana pun berjalan, sehingga tokenizer tidak dihitung sebagai komponen dalam pipeline. Komponen sesungguhnya adalah langkah yang membaca dan memperkaya objek Doc, dan setiap langkah menambahkan atribut baru tanpa menghapus atribut yang sudah ada. Model en_core_web_sm memuat enam komponen yang urutannya dapat dibaca langsung dari nlp.pipe_names, sebagaimana diperlihatkan berikut ini.
import spacy
nlp = spacy.load("en_core_web_sm")
print("tokenizer :", type(nlp.tokenizer).__name__)
print("komponen :", nlp.pipe_names)
print("bahasa :", nlp.meta["lang"])tokenizer : Tokenizer
komponen : ['tok2vec', 'tagger', 'parser', 'attribute_ruler', 'lemmatizer', 'ner']
bahasa : enUrutan tersebut bukan kebetulan, melainkan konsekuensi ketergantungan antarkomponen. Komponen tok2vec menghasilkan tensor kontekstual kecil yang dipakai bersama oleh komponen lain, sehingga komponen itu diletakkan paling depan. Tagger melabel kelas kata, parser menyusun pohon dependensi, attribute_ruler menyebarkan informasi tag ke token lain, lemmatizer memilih lemma berdasarkan tag, dan ner menandai entitas bernama di ujung barisan. Diagram berikut menggambarkan alur dari teks mentah hingga Doc yang siap dibaca.
Diagram di atas sekaligus menunjukkan titik sisip untuk komponen pihak pengguna. Komponen kustom dapat dipasang di posisi mana pun pada barisan, dan urutannya menentukan keluaran mana yang bisa dibaca. Komponen yang membutuhkan label tagger harus berada setelah tagger, sedangkan komponen yang menyediakan entitas untuk ner sebaiknya berada sebelum ner.
Komponen kustom dengan Language.component#
Komponen kustom adalah fungsi yang menerima objek Doc, menambahkan atau mengubah atributnya, lalu mengembalikan Doc yang sama. Dekorator @Language.component("nama") mendaftarkan fungsi semacam itu sebagai komponen tanpa data antarpemanggilan, sedangkan Language.factory dipakai apabila komponen menyimpan data saat inisialisasi, misalnya daftar pola yang dimuat dari konfigurasi. Komponen hasil pendaftaran dipasang melalui nlp.add_pipe("nama"), dan posisinya diatur dengan argumen before, after, first, atau last.
Kasus yang sering muncul di production adalah pola khusus domain yang tidak ada pada korpus pelatihan model, misalnya nomor tiket internal. Skrip berikut mendefinisikan komponen penanda_tiket yang mencari pola nomor tiket dengan regex, lalu memasangnya sebelum ner.
import re
import spacy
from spacy.language import Language
nlp = spacy.load("en_core_web_sm")
teks = "Return ticket TIK-2024-ABC to the front desk, and keep receipt TIK-2024-QRS."
doc = nlp(teks)
print("NER saja :", [(e.text, e.label_) for e in doc.ents])
@Language.component("penanda_tiket")
def penanda_tiket(doc):
pola = re.compile(r"TIK-\d{4}-[A-Z]{3}")
spans = []
for m in pola.finditer(doc.text):
span = doc.char_span(m.start(), m.end(), label="TIKET", alignment_mode="expand")
if span is not None:
spans.append(span)
if spans:
doc.set_ents(spans, default="outside")
return doc
nlp.add_pipe("penanda_tiket", before="ner")
print("urutan pipeline :", nlp.pipe_names)
doc = nlp(teks)
print("dengan komponen :", [(e.text, e.label_) for e in doc.ents])NER saja : [('TIK-2024-ABC', 'WORK_OF_ART')]
urutan pipeline : ['tok2vec', 'tagger', 'parser', 'attribute_ruler', 'lemmatizer', 'penanda_tiket', 'ner']
dengan komponen : [('TIK-2024-ABC', 'TIKET'), ('TIK-2024-QRS', 'TIKET')]Baris pertama keluaran memperlihatkan kelemahan model statistik. Komponen ner menebak TIK-2024-ABC sebagai WORK_OF_ART karena bentuknya mirip judul, dan tebakan itu salah. Setelah komponen dipasang dengan before="ner", urutan pipeline menunjukkan penanda_tiket tepat sebelum ner, dan kedua nomor tiket berlabel TIKET dengan benar. Prosesnya deterministik, yaitu pola regex yang sama selalu menghasilkan entitas yang sama, tanpa bergantung pada data pelatihan.
Dua detail teknis pada komponen itu patut dicatat. Metode doc.char_span memetakan rentang karakter hasil regex menjadi rentang token, karena entitas spaCy harus sejajar dengan token, dan doc.set_ents dengan default="outside" memasang semua rentang sekaligus sambil menganggap token lain berada di luar entitas.
Gabungan aturan dan model statistik#
EntityRuler adalah komponen bawaan spaCy yang menetapkan entitas dari daftar pola token, dan komponen itu dirancang untuk dipasang sebelum ner. Pembagian kerjanya sederhana, yaitu aturan deterministik menangani pola yang bentuknya tetap, sedangkan model statistik menangani pola yang berubah-ubah, misalnya tanggal dan nama orang. Gabungan semacam ini lazim di production karena pola internal sebuah organisasi hampir tidak pernah muncul pada korpus pelatihan model publik.
Skrip berikut memasang entity_ruler dengan satu pola token untuk nomor tiket, kemudian membandingkan jalur tanpa komponen statistik dengan jalur penuh.
import spacy
nlp = spacy.load("en_core_web_sm")
# pola token mengikuti hasil tokenizer, yaitu TIK-2024, -, ABC
pola_tiket = [
{"TEXT": {"REGEX": "^TIK-[0-9]{4}$"}},
{"TEXT": "-"},
{"TEXT": {"REGEX": "^[A-Z]{3}$"}},
]
ruler = nlp.add_pipe("entity_ruler", before="ner")
ruler.add_patterns([{"label": "TIKET", "pattern": pola_tiket}])
teks = "Return ticket TIK-2024-ABC to the front desk before March 3."
nonaktif = [p for p in nlp.pipe_names if p != "entity_ruler"]
doc_aturan = nlp(teks, disable=nonaktif)
print("hanya aturan :", [(e.text, e.label_) for e in doc_aturan.ents])
doc_lengkap = nlp(teks)
print("aturan + statistik :", [(e.text, e.label_) for e in doc_lengkap.ents])hanya aturan : [('TIK-2024-ABC', 'TIKET')]
aturan + statistik : [('TIK-2024-ABC', 'TIKET'), ('March 3', 'DATE')]Pada jalur pertama, hanya entity_ruler yang berjalan, sehingga satu-satunya entitas adalah TIKET. Pada jalur penuh, ner menambahkan March 3 sebagai DATE di samping hasil aturan, dan kedua sumber itu hidup berdampingan tanpa saling menimpa karena polanya tidak bertabrakan. Satu hal penting terlihat pada definisi pola, yaitu pola ditulis mengikuti hasil tokenizer, bukan bentuk permukaan teks, karena tokenizer memecah TIK-2024-ABC menjadi token TIK-2024, -, dan ABC.
Kesalahan umum#
- Memasang komponen kustom setelah ner. Komponen yang memanggil
set_entssetelah ner berjalan akan menimpa seluruh keluaran ner, karena pemanggilan itu mengganti entitas pada seluruh dokumen. Pasang komponen sebelum ner, misalnya denganbefore="ner", agar ner membaca entitas yang sudah ada dan menambahkan sisanya. - Mendaftarkan nama komponen yang sudah terdaftar. Dekorator dengan nama yang sama pada satu sesi Python memunculkan error pendaftaran ganda, dan kasus ini sering terjadi saat sel pada notebook dijalankan ulang. Gunakan nama komponen yang unik, atau jalankan ulang sesi Python dari awal sebelum mendaftarkannya kembali.
- Menganggap perubahan pipeline tersimpan otomatis. Pemanggilan
nlp.add_pipehanya mengubah objeknlppada sesi tersebut, sehingga pipeline kembali ke bentuk bawaan pada sesi berikutnya. Simpan komposisi pipeline pada kode inisialisasi yang dijalankan saat aplikasi berjalan, atau pada berkas konfigurasi yang dibacaspacy.load.
Ringkasan#
- Pipeline en_core_web_sm menjalankan enam komponen berurutan, yaitu tok2vec, tagger, parser, attribute_ruler, lemmatizer, dan ner, dengan tokenizer di luar barisan komponen.
- Komponen kustom didaftarkan melalui
@Language.componentatauLanguage.factory, dipasang melaluinlp.add_pipe, dan posisinya dikendalikan argumenbefore,after,first, ataulast. - EntityRuler yang dipasang sebelum ner memisahkan kerja aturan dari kerja statistik, sehingga pola internal tetap terdeteksi dan pola umum tetap ditangani model.
- Pola token wajib disusun dari hasil tokenisasi, karena pola yang tidak sejajar token tidak pernah cocok tanpa pesan error apa pun.
Referensi#
- spaCy Usage Documentation — Explosion
— Bagian processing-pipelines menjabarkan komponen kustom, factory, argumen posisi
add_pipe, dan penggunaan entity_ruler.