Penandaan sebagai barisan

Skema penandaan BIO dan alasan NER bukan klasifikasi per token.

Daftar isi

Topik ini membahas pelabelan barisan (sequence labeling), yaitu tugas memberi satu label pada setiap token dalam sebuah urutan dengan memperhatikan tetangganya. Fokusnya adalah skema penandaan BIO, format label standar untuk pengenalan entitas bernama. Setelah membacanya, barisan label BIO dapat disusun dari daftar entitas dan diurai kembali menjadi entitas, serta alasan NER tidak dapat diselesaikan dengan klasifikasi per token dapat dijelaskan.

Tugas pelabelan barisan#

Pelabelan barisan adalah tugas memberi label pada setiap token dari sebuah barisan, misalnya kalimat, sehingga setiap token memperoleh keluaran tersendiri. Bentuk yang paling sederhana adalah klasifikasi per token, yaitu menilai setiap token secara terpisah tanpa melihat tetangganya. Pendekatan sederhana itu tidak cukup untuk tugas-tugas yang labelnya saling berkaitan, karena label yang benar untuk sebuah token biasanya bergantung pada label token di sebelum atau sesudahnya.

Contoh tugas yang menyertai modul ini adalah pelabelan kelas kata dan pengenalan entitas bernama (named entity recognition), disingkat NER. Pada NER, label menandai apakah sebuah token berada di dalam nama orang, nama tempat, atau di luar entitas mana pun. Kata yang mengikuti penanda ke lebih mungkin bagian dari nama tempat, dan kata pada posisi awal kalimat lebih mungkin nama orang. Bukti semacam ini menyangkut posisi token di dalam barisan, bukan bentuk token itu sendiri, sehingga keputusan per token yang terpisah-pisah tidak mampu menggunakannya. Bagian berikut memperkenalkan format label yang menampung informasi barisan tersebut.

Skema penandaan BIO#

Skema BIO adalah format pelabelan barisan yang paling umum untuk NER. Namanya adalah singkatan dari Beginning, Inside, Outside, yaitu tiga peran yang dapat dipegang sebuah token. Token pertama dari sebuah entitas berlabel B- diikuti jenis entitasnya, misalnya B-PER untuk nama orang. Token berikutnya dari entitas yang sama berlabel I- dengan jenis yang sama, sedangkan token di luar entitas mana pun berlabel O.

Pemisahan label awal dan label lanjutan itulah yang menyimpan informasi batas entitas. Diagram berikut memperlihatkan skema BIO pada satu kalimat yang memuat satu nama orang dan satu nama tempat dua token.

AliberkunjungkeDanauTobaB-PEROOB-LOCI-LOCsatu entitas: Danau Toba (LOC)B- awal entitasI- lanjutan entitasO di luar entitas
Skema BIO pada kalimat Ali berkunjung ke Danau Toba

Dari diagram tersebut, tiga konvensi BIO dapat dibaca. Entitas satu token berlabel B- tanpa I- di belakangnya, entitas dua token diawali B- dan dilanjutkan I-, dan token di luar entitas selalu berlabel O. Konvensi yang sama berlaku untuk jenis entitas lain, misalnya B-ORG dan I-ORG untuk organisasi, sehingga skema ini dapat diperluas tanpa mengubah strukturnya.

Dari entitas ke BIO dan kembali#

Anotasi NER sering kali direkam sebagai daftar entitas beserta posisinya dalam kalimat, lalu dikonversi menjadi barisan BIO ketika data disiapkan untuk model. Sebaliknya, keluaran model berupa barisan label BIO yang harus diurai kembali menjadi entitas agar dapat digunakan sistem lain. Berkas berikut memuat fungsi untuk kedua arah tersebut, ditambah dekoder naif sebagai pembanding.

python bio.py
def entitas_ke_bio(token, rentang):
    """Mengubah daftar token dan rentang entitas menjadi barisan label BIO.

    rentang berisi pasangan (mulai, akhir, label) dengan akhir eksklusif.
    """
    label = ["O"] * len(token)
    for mulai, akhir, nama in rentang:
        label[mulai] = f"B-{nama}"
        for i in range(mulai + 1, akhir):
            label[i] = f"I-{nama}"
    return label


def bio_ke_entitas(token, label):
    """Mengurai barisan label BIO menjadi daftar (teks_entitas, label)."""
    hasil = []
    for i, l in enumerate(label):
        if l.startswith("B-"):
            nama = l[2:]
            teks = token[i]
            j = i + 1
            while j < len(label) and label[j] == f"I-{nama}":
                teks += " " + token[j]
                j += 1
            hasil.append((teks, nama))
    return hasil


def bio_ke_entitas_naif(token, label):
    """Dekoder naif: menganggap setiap token berlabel sebagai entitas tersendiri."""
    hasil = []
    for kata, l in zip(token, label):
        if l != "O":
            hasil.append((kata, l[2:]))
    return hasil


# uji pertama: kalimat dengan entitas satu token dan entitas dua token
kalimat1 = ["Ali", "berkunjung", "ke", "Danau", "Toba"]
label1 = entitas_ke_bio(kalimat1, [(0, 1, "PER"), (3, 5, "LOC")])
for kata, l in zip(kalimat1, label1):
    print(f"{kata:<12}{l}")
print(bio_ke_entitas(kalimat1, label1))

print()

# uji kedua: dekoder BIO versus dekoder naif tanpa pengenal awal entitas
kalimat2 = ["Danau", "Toba", "dikunjungi", "Ali", "pada", "Juni"]
label2 = entitas_ke_bio(kalimat2, [(0, 2, "LOC"), (3, 4, "PER")])
for kata, l in zip(kalimat2, label2):
    print(f"{kata:<12}{l}")
print(bio_ke_entitas(kalimat2, label2))
print(bio_ke_entitas_naif(kalimat2, label2))
text Keluaran
Ali         B-PER
berkunjung  O
ke          O
Danau       B-LOC
Toba        I-LOC
[('Ali', 'PER'), ('Danau Toba', 'LOC')]

Danau       B-LOC
Toba        I-LOC
dikunjungi  O
Ali         B-PER
pada        O
Juni        O
[('Danau Toba', 'LOC'), ('Ali', 'PER')]
[('Danau', 'LOC'), ('Toba', 'LOC'), ('Ali', 'PER')]

Pada uji pertama, fungsi entitas_ke_bio mengubah dua rentang entitas menjadi barisan label yang konsisten dengan diagram sebelumnya, dan fungsi bio_ke_entitas mengurai label itu kembali menjadi daftar entitas. Pada uji kedua, dekoder naif yang menganggap setiap token berlabel sebagai entitas tersendiri mengembalikan Danau dan Toba sebagai dua entitas terpisah, sedangkan dekoder BIO menyatukannya. Perbedaan kedua keluaran itu hanya berasal dari satu informasi, yaitu apakah awalan B- diperhatikan atau tidak.

Kedua fungsi tersebut menempati posisi tetap dalam alur kerja NER. Konversi rentang menjadi label dilakukan sekali saat data anotasi disiapkan, sedangkan penguraian label menjadi entitas dilakukan setiap kali model menghasilkan prediksi. Batas akhir rentang yang bersifat eksklusif membuat panjang entitas langsung berupa selisih posisi akhir dan posisi awal.

Mengapa NER bukan klasifikasi per token#

Argumentasi di atas dirangkum menjadi tiga alasan mengapa NER menuntut pemodelan barisan dan tidak cukup diselesaikan dengan klasifikasi per token.

  • Informasi batas tidak tersedia pada label per token. Klasifikasi per token hanya dapat menyatakan bahwa sebuah token berlabel LOC, sehingga dua token LOC berurutan tidak dapat dibedakan antara satu entitas dan dua entitas. Skema BIO menyimpan batas itu di dalam labelnya sendiri melalui pasangan B- dan I-.
  • Barisan label yang sah terbatas. Label I-LOC tidak boleh muncul tanpa B-LOC di depannya, dan label O tidak boleh berada di tengah entitas. Model per token dapat menghasilkan kombinasi yang tidak sah karena setiap keputusan diambil tanpa melihat keputusan lain.
  • Bukti konteks adalah bukti barisan. Peluang token berlabel LOC meningkat ketika token sebelumnya adalah penanda ke, dan informasi semacam itu hanya dapat digunakan apabila seluruh keputusan ditimbang bersama.

Tiga alasan itu memunculkan kebutuhan teknis yang sama, yaitu dekoder yang menimbang barisan label secara utuh. Dua model klasik yang memenuhi kebutuhan itu adalah Hidden Markov Model dan conditional random field.

Ringkasan#

  • Pelabelan barisan memberi label pada setiap token dengan menimbang tetangganya, dan NER adalah contoh utamanya pada modul ini.
  • Skema BIO membagi label menjadi B- untuk awal entitas, I- untuk lanjutan entitas, dan O untuk token di luar entitas.
  • Pengurai BIO menyatukan kembali token berlabel B- dan I- menjadi satu entitas, sedangkan dekoder naif tanpa pengenal awal merusak batasnya.
  • NER bukan klasifikasi per token karena informasi batas, sah tidaknya barisan label, dan bukti konteks semuanya menyangkut barisan, bukan token tunggal.

Referensi#