Segalanya mungkin: memecahkan masalah NLP dengan spacy





Pemrosesan bahasa alami sekarang ada di mana-mana: antarmuka suara dan bot obrolan berkembang pesat, model sedang dikembangkan untuk memproses data teks besar, dan terjemahan mesin terus berkembang.



Pada artikel ini, kita akan melihat perpustakaan SpaCy yang relatif baru, yang saat ini merupakan salah satu solusi paling populer dan nyaman untuk pemrosesan teks dengan Python. Fungsinya memungkinkan Anda menyelesaikan berbagai tugas yang sangat luas: mulai dari mengidentifikasi jenis kata dan mengekstraksi entitas bernama hingga membuat model Anda sendiri untuk dianalisis.



Untuk memulainya, mari kita lihat bagaimana data diproses di SpaCy. Teks yang dimuat untuk pemrosesan secara berurutan melewati berbagai komponen pemrosesan dan disimpan sebagai instance dari objek Doc:







Doc adalah struktur data pusat di SpaCy, di dalamnya urutan kata-kata atau, sebagaimana disebut juga, token disimpan. Di dalam objek Doc, dua tipe objek lainnya dapat dibedakan: Token dan Span. Token adalah tautan ke kata-kata individual dari sebuah dokumen, dan Span adalah tautan ke urutan beberapa kata (Anda dapat membuatnya sendiri):







Struktur data penting lainnya adalah objek Vocab, yang menyimpan sekumpulan tabel pencarian yang umum untuk semua dokumen. Ini menghemat memori dan menyediakan satu sumber informasi untuk semua dokumen yang diproses.



Token dokumen terhubung ke objek Vocab melalui hash, yang dengannya Anda bisa mendapatkan bentuk awal kata atau atribut leksikal token lainnya:







Sekarang kita tahu bagaimana penyimpanan dan pemrosesan data di pustaka SpaCy diatur. Bagaimana memanfaatkan peluang yang diberikannya? Mari kita lihat operasi yang dapat digunakan untuk memproses teks secara berurutan.



1. Operasi dasar



Sebelum Anda mulai bekerja dengan teks, Anda harus mengimpor model bahasa. Untuk bahasa Rusia, ada model resmi dari SpaCy yang mendukung tokenisasi (membagi teks menjadi token terpisah) dan sejumlah operasi dasar lainnya:



from spacy.lang.ru import Russian
      
      





Setelah mengimpor dan membuat contoh model bahasa, Anda dapat mulai memproses teks. Untuk melakukan ini, Anda hanya perlu meneruskan teks ke instance yang dibuat:



nlp = Russian()
doc = nlp("     ,   .")
      
      





Bekerja dengan objek Doc yang dihasilkan sangat mirip dengan bekerja dengan daftar: Anda dapat mengakses token yang diinginkan dengan indeks atau membuat potongan dari beberapa token. Dan untuk mendapatkan teks token atau slice, Anda dapat menggunakan atribut text:



token = doc[0]
print(token.text)

span = doc[3:6]
print(span.text)


  
      
      





Untuk informasi lebih lanjut tentang tipe informasi apa yang terkandung dalam token, atribut berikut dapat digunakan:



  1. is_alpha - periksa apakah token hanya berisi karakter alfabet
  2. is_punct - periksa apakah tokennya adalah tanda baca
  3. like_num - periksa apakah token adalah angka


print("is_alpha:    ", [token.is_alpha for token in doc])
print("is_punct:    ", [token.is_punct for token in doc])
print("like_num:    ", [token.like_num for token in doc])

      
      





Mari pertimbangkan contoh lain, di mana semua token yang mendahului titik ditampilkan di layar. Untuk mendapatkan hasil ini, saat melakukan iterasi terhadap token, periksa token berikut menggunakan atribut token.i:



for token in doc:
    if token.i+1 < len(doc):
        next_token = doc[token.i+1]
        if next_token.text == ".":
            print(token.text)


      
      





2. Operasi dengan sintaks



Untuk operasi pemrosesan kata yang lebih kompleks, model lain digunakan. Mereka secara khusus dilatih untuk tugas-tugas yang berkaitan dengan sintaksis, ekstraksi entitas bernama, dan bekerja dengan arti kata. Misalnya, untuk bahasa Inggris, ada 3 model resmi yang ukurannya berbeda-beda. Untuk bahasa Rusia, saat ini model resmi belum dilatih, tetapi sudah ada model ru2 dari sumber pihak ketiga yang dapat bekerja dengan sintaks.



Di akhir artikel ini, kami akan membahas cara membuat model Anda sendiri atau melatih model yang sudah ada agar berfungsi lebih baik untuk tugas tertentu.



Untuk menggambarkan sepenuhnya kemampuan SpaCy, kami akan menggunakan model bahasa Inggris di artikel ini. Mari kita siapkan model en_core_web_sm kecil, yang bagus untuk mendemonstrasikan berbagai kemungkinan. Untuk menginstalnya di baris perintah, Anda perlu mengetik:



python -m spacy download en_core_web_sm
      
      





Dengan menggunakan model ini, kita bisa mendapatkan untuk setiap token part of speech, peran dalam kalimat, dan token yang bergantung padanya:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("New Apple MacBook set launch tomorrow")

for token in doc:
    token_text = token.text
    token_pos = token.pos_
    token_dep = token.dep_
    token_head = token.head.text
    print(f"{token_text:<12}{token_pos:<10}" \
          f"{token_dep:<10}{token_head:<12}")
      
      





New         PROPN     compound  MacBook     
Apple       PROPN     compound  MacBook     
MacBook     PROPN     nsubj     set         
set         VERB      ROOT      set         
to          PART      aux       launch      
launch      VERB      xcomp     set         
tomorrow    NOUN      npadvmod  launch 
      
      





Sejauh ini, cara terbaik untuk melihat dependensi bukanlah dengan membaca data teks, tetapi membangun pohon sintaks. Fungsi perpindahan dapat membantu dengan ini, yang Anda hanya perlu mentransfer dokumen:



from spacy import displacy
displacy.render(doc, style='dep', jupyter=True)
      
      





Sebagai hasil dari mengeksekusi kode, kita mendapatkan pohon tempat semua informasi sintaksis tentang kalimat tersebut berada:







Untuk menguraikan nama tag, Anda dapat menggunakan fungsi menjelaskan:



print(spacy.explain("aux"))
print(spacy.explain("PROPN"))
auxiliary
proper noun
      
      





Di sini, singkatan ditampilkan di layar, dari mana kita dapat mempelajari bahwa aux adalah singkatan dari partikel pembantu (auxiliary), dan PROPN adalah kata benda yang tepat.



SpaCy juga menerapkan kemampuan untuk mengetahui bentuk awal kata untuk salah satu token (-PRON- digunakan untuk kata ganti):



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("I saw a movie yesterday")
print(' '.join([token.lemma_ for token in doc]))

'-PRON- see a movie yesterday'
      
      





3. Menyoroti entitas bernama



Seringkali, untuk bekerja dengan teks, Anda perlu menyoroti entitas yang disebutkan dalam teks. Atribut doc.ents digunakan untuk mencantumkan entitas bernama dalam dokumen, dan atribut ent.label_ digunakan untuk mendapatkan label untuk entitas itu:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for 1$ billion")
for ent in doc.ents:
    print(ent.text, ent.label_)


Apple ORG
U.K. GPE
1$ billion MONEY
      
      





Anda juga dapat menggunakan atribut menjelaskan di sini untuk melihat decoding label entitas bernama:



print(spacy.explain("GPE"))

      
      





Negara, kota, negara bagian

Dan fungsi perpindahan akan membantu Anda memvisualisasikan daftar entitas tepat di teks:



dari spacy import displacy

displacy.render (doc, style = 'ent', jupyter = True)







4. Buat template Anda sendiri untuk pencarian teks



Modul spaCy berisi alat yang sangat berguna yang memungkinkan Anda membuat templat pencarian teks Anda sendiri. Secara khusus, Anda dapat mencari kata-kata dari bagian pidato tertentu, semua bentuk kata dengan bentuk awalnya, memeriksa jenis konten di token. Berikut adalah daftar parameter utama:







Mari kita coba membuat template kita sendiri untuk mengenali urutan token. Katakanlah kita ingin mengekstrak baris dari teks tentang Piala Dunia Kriket FIFA atau ICC dengan menyebutkan tahun:



import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab)
pattern = [
    {"IS_DIGIT": True}, 
    {"LOWER": {"REGEX": "(fifa|icc)"}},
    {"LOWER": "cricket", "OP": "?"},
    {"LOWER": "world"},
    {"LOWER": "cup"}
]
matcher.add("fifa_pattern", None, pattern)
doc = nlp("2018 ICC Cricket World Cup: Afghanistan won!")
matches = matcher(doc)
for match_id, start, end in matches:
    matched_span = doc[start:end]
    print(matched_span)
      
      





2018 ICC Cricket World Cup
      
      





Jadi, dalam blok kode ini, kami mengimpor objek Matcher khusus yang memungkinkan kami menyimpan satu set templat khusus. Setelah memulainya, kami membuat template tempat kami menentukan urutan token. Harap perhatikan bahwa kami menggunakan ekspresi reguler untuk memilih antara ICC dan FIFA, dan untuk token Cricket - kunci yang menunjukkan keberadaan opsional token ini.



Setelah membuat template, Anda perlu menambahkannya ke set menggunakan fungsi add, dengan menentukan ID template unik di parameter. Hasil pencarian disajikan dalam bentuk daftar tupel. Setiap tupel terdiri dari ID pertandingan dan indeks awal dan akhir dari potongan yang ditemukan dalam dokumen.



5. Penentuan kedekatan semantik



Dua kata bisa sangat mirip artinya, tetapi bagaimana Anda mengukur kedekatannya? Dalam tugas seperti itu, vektor semantik dapat membantu. Jika dua kata atau ekspresi verbose serupa, vektornya akan berdekatan satu sama lain.



Menghitung kedekatan semantik vektor di SpaCy tidaklah sulit jika model bahasa telah dilatih untuk memecahkan masalah tersebut. Hasilnya sangat bergantung pada ukuran model, jadi mari kita ambil model yang lebih besar untuk tugas ini:



import spacy
      
      





nlp = spacy.load("en_core_web_md")
doc1 = nlp("I like burgers")
doc2 = nlp("I like pizza")
print(doc1.similarity(doc2))
      
      





0.9244169833828932
      
      





Nilainya dapat berkisar dari nol hingga satu: semakin dekat ke satu, semakin besar kesamaannya. Dalam contoh di atas, kami membandingkan dua dokumen, namun, Anda dapat membandingkan token dan potongan individual dengan cara yang sama.



Penilaian kedekatan semantik dapat berguna untuk memecahkan banyak masalah. Misalnya, Anda dapat menggunakannya untuk menyiapkan sistem rekomendasi sehingga ia menawarkan teks serupa kepada pengguna berdasarkan teks yang sudah dibaca.



Penting untuk diingat bahwa afinitas semantik sangat subjektif dan selalu bergantung pada konteks tugas. Misalnya, frasa "Saya suka anjing" dan "Saya benci anjing" adalah serupa, karena keduanya mengungkapkan pendapat tentang anjing, tetapi pada saat yang sama, suasana hatinya sangat berbeda. Dalam beberapa kasus, Anda harus melatih model bahasa tambahan agar hasilnya sesuai dengan konteks masalah Anda.



6. Membuat komponen pemrosesan Anda sendiri



Modul SpaCy mendukung sejumlah komponen bawaan (tokenizer, penyorotan entitas bernama), tetapi juga memungkinkan Anda untuk menentukan komponen Anda sendiri. Faktanya, komponen secara berurutan disebut fungsi yang mengambil dokumen sebagai input, mengubahnya, dan mengirimnya kembali. Komponen baru dapat ditambahkan menggunakan atribut add_pipe:



import spacy

def length_component(doc):
    doc_length = len(doc)
    print(f"This document is {doc_length} tokens long.")
    return doc

nlp = spacy.load("en_core_web_sm")
nlp.add_pipe(length_component, first=True)
print(nlp.pipe_names)
doc = nlp("This is a sentence.")
      
      





['length_component', 'tagger', 'parser', 'ner']
This document is 5 tokens long.
      
      





Dalam contoh di atas, kami membuat dan menambahkan fungsi kami sendiri yang menampilkan jumlah token dalam dokumen yang diproses. Dengan menggunakan atribut nlp.pipe_names, kita mendapatkan urutan eksekusi komponen: seperti yang bisa kita lihat, komponen yang dibuat adalah yang pertama dalam daftar. Anda dapat menggunakan opsi berikut untuk menentukan tempat untuk menambahkan komponen baru:







Kemampuan untuk menambahkan komponen khusus adalah alat yang sangat ampuh untuk mengoptimalkan pemrosesan untuk kebutuhan Anda.



7. Pelatihan dan pembaruan model



Model statistik membuat prediksi berdasarkan contoh yang mereka pelajari. Biasanya, keakuratan model tersebut dapat ditingkatkan dengan melatih model tersebut dengan contoh khusus untuk tugas Anda. Pelatihan tambahan tentang model yang ada bisa sangat berguna (misalnya, untuk pengenalan atau penguraian entitas bernama).



Contoh pelatihan tambahan dapat ditambahkan langsung di antarmuka SpaCy. Contoh itu sendiri harus terdiri dari data teks dan daftar label untuk contoh ini yang akan dilatih oleh model.



Sebagai ilustrasi, pertimbangkan untuk memperbarui model untuk mengambil entitas bernama. Untuk memperbarui model seperti itu, Anda harus memberikan banyak contoh yang berisi teks, indikasi entitas dan kelasnya. Dalam contoh, Anda perlu menggunakan seluruh klausa, karena saat mengekstrak entitas, model sangat bergantung pada konteks klausa. Sangat penting untuk melatih model secara komprehensif sehingga dapat mengenali token non-entitas.



Contohnya:



("What to expect at Apple's 10 November event", {"entities": [(18,23,"COMPANY")]})
("Is that apple pie I smell?", {"entities": []})
      
      





Dalam contoh pertama, sebuah perusahaan disebutkan: untuk pelatihan, kami menyoroti posisi di mana namanya dimulai dan diakhiri, dan kemudian kami meletakkan label kami bahwa entitas ini adalah sebuah perusahaan. Pada contoh kedua, kita berbicara tentang buah, jadi tidak ada entitas.



Data untuk melatih model biasanya di-markup oleh orang-orang, tetapi pekerjaan ini dapat sedikit diotomatiskan menggunakan templat pencarian sendiri di SpaCy atau program markup khusus (misalnya, Prodigy ).



Setelah contoh disiapkan, Anda dapat langsung melanjutkan ke pelatihan model. Agar model dapat dilatih secara efektif, Anda perlu menjalankan serangkaian beberapa pelatihan. Dengan setiap pelatihan, model akan mengoptimalkan bobot parameter tertentu. Model di SpaCy menggunakan teknik penurunan gradien stokastik, jadi ada baiknya untuk mencampur contoh dengan setiap pelatihan, dan juga mengirimkannya dalam porsi kecil (paket). Ini akan meningkatkan keandalan perkiraan gradien.







import spacy
import random
from spacy.lang.en import English

TRAINING_DATA = [
    ("What to expect at Apple's 10 November event", 
    {"entities": [(18,23,"COMPANY")]})
    #  ...
]

nlp = English()

for i in range(10):
    random.shuffle(TRAINING_DATA)
    for batch in spacy.util.minibatch(TRAINING_DATA):
        texts = [text for text, annotation in batch]
        annotations = [annotation for text, annotation in batch]
        nlp.update(texts, annotations)
        
nlp.to_disk("model")
      
      





Pada contoh di atas, loop terdiri dari 10 pelatihan. Setelah menyelesaikan pelatihan, model disimpan ke disk di folder model.



Untuk kasus ketika tidak hanya perlu memperbarui, tetapi untuk membuat model baru, sejumlah operasi diperlukan sebelum memulai pelatihan.



Pertimbangkan proses pembuatan model baru untuk menyorot entitas bernama:



nlp = spacy.blank("en")
ner = nlp.create_pipe("ner")
nlp.add_pipe(ner)
ner.add_label("COMPANY")
nlp.begin_training()
      
      





Pertama, kita membuat model kosong menggunakan fungsi spacy.blank ("en"). Model hanya berisi data bahasa dan aturan tokenisasi. Kemudian kami menambahkan komponen ner yang bertanggung jawab untuk menyorot entitas bernama, dan menggunakan atribut add_label, tambahkan label untuk entitas tersebut. Kemudian kami menggunakan fungsi nlp.begin_training () untuk menginisialisasi model untuk pelatihan dengan distribusi bobot acak. Nah, itu cukup untuk melatih model, seperti yang ditunjukkan pada contoh sebelumnya.



All Articles