Update Nov 2021: walaupun sudah berumur 3 tahun, posting ini ternyata masih cukup banyak yang mengakses. Bagi yang membutuhkan pretrained Glove data wikipedia Bahasa Indonesia (50 dimensi), dapat mendownloadnya di: https://drive.google.com/file/d/1jgnvIEp8rE3dh68lZXBHfyxzmeky9z6w/view?usp=sharing Pretrained ini dibuat tahun 2018, jadi saya tidak tahu apakah masih bisa digunakan sekarang di 2021, dan mohon jangan kontak saya tentang ini 🙂 Lagipula ada teknik lain seperti BERT, GPT, XLNet yang kemungkinan besar kinerjanya lebih baik.
— end update —
Sebelumnya saya sudah membuat vector word2vec Wikipedia Bhs Indonesia dengan Gensim. Posting ini akan membahas model embedded word yang lain yaitu GloVe. Saya akan gunakan untuk task NER. Pengalaman saya dulu untuk task textual entailment bahasa Inggris, Glove lebih baik daripada Word2Vec.
Untuk GloVe, saya tidak menemukan implementasinya dalam Python, yang ada adalah dari penulisnya langsung dalam C. Berikut langkah-langkahnya.
- Download source code dari https://nlp.stanford.edu/projects/glove/
- Ekstrak dan masuk ke directorynya, lalu ketik “make” untuk mem-build source code.
- Jalankan ./demo.sh demo ini akan mendownload data text8 sekitar 30MB. Jika berhasil artinya program bisa kita gunakan.
- Siapkan file teks gabungan dari artikel wikipedia bahasa indonesia (posting saya tentang ini)
- Ubah demo.sh jadi seperti ini. File input ada di variabel CORPUS, file output ada di variabel SAVE_FILE. Saya buang bagian download file dan bagian evaluasi.
#!/bin/bash CORPUS=wiki.id.case.text VOCAB_FILE=vocab.txt COOCCURRENCE_FILE=cooccurrence.bin COOCCURRENCE_SHUF_FILE=cooccurrence.shuf.bin BUILDDIR=build SAVE_FILE=glove_wiki_id_50 VERBOSE=2 MEMORY=4.0 VOCAB_MIN_COUNT=5 VECTOR_SIZE=50 MAX_ITER=15 WINDOW_SIZE=15 BINARY=2 NUM_THREADS=8 X_MAX=10 $BUILDDIR/vocab_count -min-count $VOCAB_MIN_COUNT -verbose $VERBOSE $VOCAB_FILE if [[ $? -eq 0 ]] then $BUILDDIR/cooccur -memory $MEMORY -vocab-file $VOCAB_FILE -verbose $VERBOSE -window-size $WINDOW_SIZE $COOCCURRENCE_FILE if [[ $? -eq 0 ]] then $BUILDDIR/shuffle -memory $MEMORY -verbose $VERBOSE $COOCCURRENCE_SHUF_FILE if [[ $? -eq 0 ]] then $BUILDDIR/glove -save-file $SAVE_FILE -threads $NUM_THREADS -input-file $COOCCURRENCE_SHUF_FILE -x-max $X_MAX -iter $MAX_ITER -vector-size $VECTOR_SIZE -binary $BINARY -vocab-file $VOCAB_FILE -verbose $VERBOSE fi fi fi
Untuk mencoba hasilnya, kita bisa gunakan code sebelumnya karena Gensim bisa mengkonversi file GloVe.
Konversi dari Glove ke word2vec (diambil dari: https://radimrehurek.com/gensim/scripts/glove2word2vec.html)
from gensim.test.utils import datapath, get_tmpfile from gensim.models import KeyedVectors from gensim.scripts.glove2word2vec import glove2word2vec namaFileGlove = "glove_wiki_id.txt" glove_file = datapath(namaFileGlove) tmp_file = get_tmpfile("w2vec_glove_wiki_id.txt") glove2word2vec(glove_file, tmp_file)
Sekarang kita coba dengan code yang sama dengan Word2Vec sebelumnya (untuk load gunakan KeyedVectors.load_word2vec_format). Supaya sama, saya gunakan ukuran VECTOR_SIZE=400, walaupun prosesnya jadi lebih lama dan filenya lebih besar.
from gensim.models import KeyedVectors namaFileModel = "w2vec_glove_wiki_id.txt" model = KeyedVectors.load_word2vec_format(namaFileModel) hasil = model.most_similar("Bandung") print("Bandung:{}".format(hasil)) hasil = model.most_similar("tempo") print("tempo:{}".format(hasil)) hasil = model.most_similar("Tempo") print("Tempo:{}".format(hasil)) hasil = model.most_similar("Soekarno") print("Soekarno:{}".format(hasil)) sim = model.similarity("bakso", "nasi") print("Kedekatan bakso-nasi: {}".format(sim)) sim = model.similarity("bakso", "pecel") print("Kedekatan bakso-pecel: {}".format(sim)) sim = model.similarity("bakso", "mobil") print("Kedekatan bakso-mobil: {}".format(sim)) hasil = model.most_similar_cosmul(positive=['perempuan', 'raja'], negative=['pria']) print("pria-raja, perempuan-?: {}".format(hasil)) hasil = model.most_similar_cosmul(positive=['perempuan', 'raja'], negative=['lelaki']) print("lelaki-raja, perempuan-?:{}".format(hasil)) hasil = model.most_similar_cosmul(positive=['minuman', 'mangga'], negative=['buah']) print("buah-mangga, minuman-?:{}".format(hasil))
Hasilnya sebagai berikut
Bandung:[('Bogor', 0.5553832650184631), ('Surabaya', 0.5533844232559204), ('Jakarta', 0.5264717936515808), ('Medan', 0.5121393203735352), ('Semarang', 0.4910121262073517), ('Yogyakarta', 0.4880320131778717), ('Malang', 0.48358896374702454), ('Jawa', 0.4750467836856842), ('ITB', 0.4737907946109772), ('Persib', 0.4654899537563324)] tempo:[('indonesiana', 0.5886592268943787), ('doeloe', 0.5427557229995728), ('putu_suasta', 0.48804518580436707), ('tapin', 0.46188244223594666), ('https', 0.41826149821281433), ('cepat', 0.40567928552627563), ('ketukan', 0.4037955701351166), ('irama', 0.3982717990875244), ('lambat', 0.39812949299812317), ('maestoso', 0.39417707920074463)] Tempo:[('Majalah', 0.54466712474823), ('Koran', 0.5328548550605774), ('Doeloe', 0.5282064080238342), ('majalah', 0.4538464844226837), ('Kompas', 0.4463438391685486), ('wartawan', 0.4179822504520416), ('koran', 0.41709277033805847), ('Harian', 0.40668201446533203), ('Republika', 0.3915051221847534), ('Post', 0.38742369413375854)] Soekarno:[('Hatta', 0.6839763522148132), ('Soeharto', 0.5900896787643433), ('Sukarno', 0.5895135998725891), ('Bung', 0.49154624342918396), ('Vannico', 0.4613707363605499), ('Megawati', 0.46065616607666016), ('Karno', 0.4603942334651947), ('Presiden', 0.4588601887226105), ('Ekki', 0.45219823718070984), ('WIII', 0.4458869993686676)] Kedekatan bakso-nasi: 0.33218569528946 Kedekatan bakso-pecel: 0.3385669314106577 Kedekatan bakso-mobil: 0.1036423556873547 pria-raja, perempuan-?: [('Raja', 0.8700850605964661), ('kerajaan', 0.8684984445571899), ('Yehuda', 0.8591107130050659), ('cucu', 0.8312298059463501), ('AbiMilki', 0.821474552154541), ('memerintah', 0.8194707632064819), ('saudara', 0.8159937262535095), ('Daud', 0.8155518770217896), ('Kerajaan', 0.8149770498275757), ('penguasa', 0.8049719333648682)] lelaki-raja, perempuan-?:[('Raja', 0.9214608669281006), ('kerajaan', 0.919419527053833), ('Kerajaan', 0.8668190240859985), ('AbiMilki', 0.8551638722419739), ('ratu', 0.8542945384979248), ('penguasa', 0.8345737457275391), ('terakhir', 0.8345482349395752), ('disebutkan', 0.8269140720367432), ('istana', 0.82608562707901), ('istri', 0.8246856331825256)] buah-mangga, minuman-?:[('beralkohol', 0.7880735397338867), ('Schorle', 0.7836616039276123), ('bersoda', 0.7783095240592957), ('manggaan', 0.7711527943611145), ('jeruk', 0.7603545784950256), ('anggur', 0.7549997568130493), ('Minuman', 0.7476464509963989), ('Frappuccino', 0.740592360496521), ('jahe', 0.7360817790031433), ('mocha', 0.7357983589172363)]
Penasaran, berikut hasil kalau vector_size-nya 50 (default)
Bandung:[('Surabaya', 0.8777784109115601), ('Malang', 0.8505295515060425), ('Jakarta', 0.8406218886375427), ('Medan', 0.8344693183898926), ('Semarang', 0.8225082159042358), ('Yogyakarta', 0.8207614421844482), ('Bogor', 0.8181610703468323), ('Makassar', 0.7571447491645813), ('Tangerang', 0.7515754699707031), ('Solo', 0.7264706492424011)] tempo:[('doeloe', 0.7084428668022156), ('indonesiana', 0.6802346706390381), ('read', 0.6363065242767334), ('pas', 0.6065201759338379), ('indonesia', 0.5810031890869141), ('pda', 0.5744251608848572), ('putu_suasta', 0.5698538422584534), ('nada', 0.5527507066726685), ('html', 0.5519558787345886), ('irama', 0.5514932870864868)] Tempo:[('Koran', 0.8052877187728882), ('Majalah', 0.7781724333763123), ('Kompas', 0.7708441019058228), ('Gramedia', 0.7339286208152771), ('Penerbit', 0.7299134731292725), ('Harian', 0.7244901657104492), ('Republika', 0.7203424572944641), ('koran', 0.7195203900337219), ('KOMPAS', 0.7062090635299683), ('Doeloe', 0.7039147615432739)] Soekarno:[('Hatta', 0.876067042350769), ('Sukarno', 0.8076358437538147), ('Soeharto', 0.7557047605514526), ('Bung', 0.7302334308624268), ('kemerdekaan', 0.7065078616142273), ('Karno', 0.6804633736610413), ('Basuki', 0.6803600788116455), ('Kemerdekaan', 0.6702237129211426), ('Yudhoyono', 0.6673594117164612), ('Susilo', 0.6618077754974365)] Kedekatan bakso-nasi: 0.6207393500954625 Kedekatan bakso-pecel: 0.5784330569151002 Kedekatan bakso-mobil: 0.28361517810153536 pria-raja, perempuan-?: [('Yehuda', 0.9973295331001282), ('memerintah', 0.9838510155677795), ('Herodes', 0.9673323631286621), ('Raja', 0.9654756784439087), ('Daud', 0.9616796970367432), ('putranya', 0.9616104960441589), ('kerajaan', 0.9497379660606384), ('cucu', 0.9484671950340271), ('Firaun', 0.947074830532074), ('menantu', 0.9469170570373535)] lelaki-raja, perempuan-?:[('kerajaan', 1.0183593034744263), ('memerintah', 1.0134179592132568), ('penguasa', 1.0113284587860107), ('Raja', 0.9971156716346741), ('Kerajaan', 0.9939565658569336), ('takhta', 0.9919894933700562), ('tahta', 0.9914684891700745), ('istana', 0.9877175092697144), ('kekuasaan', 0.983529269695282), ('MANURUNGNGE', 0.9810593128204346)] buah-mangga, minuman-?:[('Arak', 1.0535870790481567), ('Crawlers', 0.9980041980743408), ('Carpet', 0.9971945285797119), ('Rimpang', 0.
Sepertinya untuk analogi lebih bagus Word2Vec. Berbeda dengan word2vec, Bakso-nasi lebih dekat dibandingkan bakso-pecel. Hasil kedekatan kata juga berbeda. Kalau lihat sekilas sepertinya lebih bagus Word2Vec, tapi saat saya coba untuk task NER, lebih bagus GloVe (naik dari 0.70 ke 0.72 untuk ukuran 50 sedangkan untuk ukuran vector 400 hasilnya hanya naik sedikit). Mungkin perlu buat dataset untuk evaluasi word embedding ini.
Update:
Jika mau men-train dokumen Bahasa Inggris di demo.sh ada fungsi untuk mengevaluasi, code pythonnya menggunakan Python2 dan lib numpy, jika ingin menggunakan virtualenv, langkahnya sbb:
masuk ke direktory Glove,
mkdir virtenv
virtualenv -p /usr/bin/python2 virtenv
source virtenv/bin/activate
pip install numpy
Update demo.sh sebelum pemanggilan evaluate:
Perbedaan glove dengan word2vec itu sendiri terletak dimananya ya pak?
Bisa lihat papernya, tapi intinya sih GloVe menggunakan count global, sedangkan word2vec hanya count sebatas ukuran window.
Selamat pagi pak, bolehkah saya meminta hasil traing glove dengan bahasa Indonesia? Karena saya sudah mencoba cara yg bapak jelaskan diatas, namun masih belum bisa. Terimakasih pak
Lumayan besar kalau diupload (perasaan dulu saya pernah upload tapi lupa dimana). Saran saya lebih baik cari library python, sudah ada beberapa (googling dengan keyword python glove).
Selamat malam bapak, saat menggunakan perintah make sesuai step ke-2 di cmd muncul galat seperti ini :
D:\PI\nlp\Glovee\GloVe-1.2>mingw32-make
mkdir -p build
gcc src/glove.c -o build/glove -lm -pthread -Ofast -march=native -funroll-loops
-Wno-unused-result
src/glove.c: In function ‘initialize_parameters’:
src/glove.c:67:6: warning: implicit declaration of function ‘posix_memalign’ [-W
implicit-function-declaration]
a = posix_memalign((void **)&W, 128, 2 * vocab_size * vector_size * sizeof(rea
l)); // Might perform better than malloc
^~~~~~~~~~~~~~
C:\Users\GARRYD~1\AppData\Local\Temp\ccPP5xSX.o:glove.c:(.text+0xb73): undefined
reference to `posix_memalign’
C:\Users\GARRYD~1\AppData\Local\Temp\ccPP5xSX.o:glove.c:(.text+0xba5): undefined
reference to `posix_memalign’
collect2.exe: error: ld returned 1 exit status
mingw32-make: *** [Makefile:12: glove] Error 1
D:\PI\nlp\Glovee\GloVe-1.2>
kira-kira kenapa yaa pak?
terima kasih atas ilmunya..
coba dengan LInux? mayoritas tools deep learning dibuat dengan Linux, jadi sering porting ke Windowsnya kurang mendapat perhatian.
terima kasih atas respon yang diberikan..
sudah dicoba bapak, setelah eksekusi program demo.sh program stuck pada ‘BUILIDING VOCABULARY processed 0 token’
coba gunakan WSL, kalau mas nya makai windows
pak apakah ada paper yang menunjukan kelebihan word2vec dibandingkan dengan glove?
Glove dibuat setelah Word2Vec, jadi akan sulit cari paper yang menunjuukkan kelebihan Word2Vec daripada Glove. Tapi sekarang sih sudah banyak yang lebih baik Glove, jadi diskusi antara Glove vs Word2Vec sudah tidak relevan lagi.
Selamat siang Pak, saya sudah mengikuti langkah-langkah yang Bapak berikan untuk melakukan embedding word dengan GloVe. Namun untuk hasil similarity dan lainnya, berbeda jauh dari yang Bapak hasilkan. Kira-kira itu karena faktor apa ya Pak?
Untuk variablenya saya samakan dengan code pada artikel ini. Dengan korpora wikipedia terbaru dan dijalankan di linux. Terimakasih sebelumnya.
Artikel di blog ini dibuat 2 tahun lalu, library-nya kemungkinan sudah berubah banyak.