
BERT adalah jaringan saraf dari Google, yang ditunjukkan oleh hasil margin yang canggih pada sejumlah tugas. Menggunakan BERT, Anda dapat membuat program AI untuk memproses bahasa alami: jawab pertanyaan yang diajukan dalam bentuk apa pun, buat bot obrolan, penerjemah otomatis, analisis teks, dan sebagainya.
Google telah memposting model BERT yang sudah dilatih sebelumnya, tetapi seperti biasanya dengan Machine Learning, mereka mengalami kekurangan dokumentasi. Oleh karena itu, dalam tutorial ini kita akan belajar cara menjalankan jaringan saraf BERT di komputer lokal, serta pada server GPU gratis di Google Colab.
Mengapa itu perlu sama sekali
Untuk mengirimkan teks ke input jaringan saraf, Anda harus menyajikannya dalam bentuk angka. Paling mudah untuk melakukan surat ini dengan surat, menerapkan satu huruf untuk setiap pintu masuk jaringan saraf. Kemudian setiap huruf akan dikodekan dengan angka dari 0 hingga 32 (ditambah beberapa jenis margin untuk tanda baca). Ini yang disebut level karakter.
Tetapi hasil yang jauh lebih baik diperoleh jika kami menyajikan proposal tidak dengan satu huruf, tetapi dengan mengirimkan ke setiap input jaringan saraf segera seluruh kata (atau setidaknya suku kata). Itu sudah akan menjadi level kata. Opsi termudah adalah mengkompilasi kamus dengan semua kata yang ada, dan memberi makan jaringan jumlah kata dalam kamus ini. Misalnya, jika kata "anjing" ada di kamus ini di tempat 1678, maka kita memasukkan angka 1678 untuk input dari jaringan saraf untuk kata ini.
Tetapi hanya dalam bahasa alami, dengan kata "anjing", banyak asosiasi muncul sekaligus dalam diri seseorang: "lembut", "jahat", "teman seseorang". Mungkinkah untuk menyandikan fitur pemikiran kita ini dalam presentasi untuk jaringan saraf? Ternyata kamu bisa. Untuk melakukan ini, cukup dengan menyusun ulang angka kata sehingga kata-kata yang dekat artinya berdiri berdampingan. Misalnya, untuk "anjing" angka 1678, dan untuk kata "mengembang" angka 1680. Dan untuk kata "teko" jumlahnya 9000. Seperti yang Anda lihat, angka 1678 dan 1680 lebih dekat satu sama lain daripada angka 9000.
Dalam praktiknya, setiap kata diberikan bukan satu angka, tetapi beberapa - satu vektor, katakanlah, dari 32 angka. Dan jarak diukur sebagai jarak antara titik-titik yang ditunjukkan oleh vektor-vektor ini dalam ruang dimensi yang sesuai (untuk vektor 32 digit panjangnya, ini adalah ruang dengan 32 dimensi, atau dengan 32 sumbu). Ini memungkinkan Anda untuk membandingkan satu kata sekaligus dengan beberapa kata yang hampir memiliki makna (tergantung pada sumbu mana yang harus dihitung). Selain itu, operasi aritmatika dapat dilakukan dengan vektor. Contoh klasik: jika Anda mengurangi vektor "pria" dari vektor yang menunjukkan kata "raja" dan menambahkan vektor untuk kata "wanita", Anda mendapatkan vektor hasil tertentu. Dan dia secara ajaib akan sesuai dengan kata "ratu". Dan memang, "raja adalah pria + wanita = ratu." Keajaiban! Dan ini bukan contoh abstrak, tetapi itu benar - benar terjadi . Mempertimbangkan bahwa jaringan saraf diadaptasi dengan baik untuk transformasi matematis atas input mereka, ini tampaknya memberikan efisiensi yang tinggi dari metode ini.
Pendekatan ini disebut Embeddings. Semua paket pembelajaran mesin (TensorFlow, PyTorch) memungkinkan lapisan pertama dari jaringan saraf untuk menempatkan lapisan khusus dari Lapisan Penanaman, yang melakukan ini secara otomatis. Artinya, pada input dari jaringan saraf kita mengirimkan nomor kata yang biasa dalam kamus, dan Embedding Layer, belajar mandiri, menerjemahkan setiap kata ke dalam vektor dengan panjang yang ditentukan, katakanlah, 32 angka.
Tetapi mereka segera menyadari bahwa jauh lebih menguntungkan untuk melakukan pra-pelatihan representasi vektor kata-kata seperti itu pada beberapa kumpulan besar teks, misalnya, di seluruh Wikipedia, dan menggunakan vektor kata yang sudah jadi dalam jaringan saraf tertentu, daripada mengajar mereka lagi setiap kali.
Ada beberapa cara untuk mewakili kata sebagai vektor, mereka berevolusi secara bertahap: word2vec, GloVe, Elmo.
Pada musim panas 2018, OpenAI memperhatikan bahwa jika Anda melakukan pra-latih jaringan saraf pada arsitektur Transformer pada volume teks yang besar, maka secara tak terduga dan dengan margin yang besar menunjukkan hasil yang sangat baik dalam berbagai jenis tugas pemrosesan bahasa alami. Bahkan, jaringan saraf seperti itu pada keluarannya menciptakan representasi vektor untuk kata-kata, dan bahkan seluruh frasa. Dan dengan menggantung di atas model bahasa semacam itu satu blok kecil sepasang lapisan neuron tambahan, Anda dapat melatih jaringan saraf ini untuk tugas apa pun.
BERT dari Google adalah jaringan IPK lanjutan dari OpenAI (dua arah bukan satu arah, dll.), Juga berdasarkan pada arsitektur Transformer. Saat ini, BERT canggih di hampir semua tolok ukur NLP populer.
Bagaimana mereka melakukannya
Gagasan di balik BERT sangat sederhana: mari memberi makan di jaringan saraf dengan frasa di mana kita mengganti 15% dari kata-kata dengan [MASK], dan melatih jaringan saraf untuk memprediksi kata-kata bertopeng ini.
Sebagai contoh, jika kita mengirim frasa βAku datang ke [MASK] dan membeli [MASK]β ke input dari jaringan saraf, itu akan menunjukkan kata βsimpanβ dan βsusuβ di output. Ini adalah contoh yang disederhanakan dari halaman BERT resmi, pada kalimat yang lebih panjang, kisaran opsi yang mungkin menjadi lebih kecil, dan respon dari jaringan saraf tidak ambigu.
Dan agar jaringan saraf untuk belajar memahami hubungan antara kalimat yang berbeda, kami juga akan melatihnya untuk memprediksi apakah kalimat kedua adalah kelanjutan logis dari kalimat pertama. Atau apakah itu frase acak yang tidak ada hubungannya dengan yang pertama.
Jadi, untuk dua kalimat: "Saya pergi ke toko." dan "Dan membeli susu di sana.", jaringan saraf harus menjawab bahwa ini logis. Dan jika frasa kedua adalah "Crucian sky Pluto", maka saya harus menjawab bahwa proposal ini tidak ada hubungannya dengan yang pertama. Kami akan bermain-main dengan kedua mode BERT di bawah ini.
Setelah melatih jaringan saraf pada badan teks dari Wikipedia dan koleksi buku BookCorpus selama 4 hari di 16 TPU, kami mendapat BERT.
Instalasi dan pengaturan
Catatan : di bagian ini kami akan meluncurkan dan bermain dengan BERT di komputer lokal. Untuk menjalankan jaringan saraf ini pada GPU lokal, Anda membutuhkan NVidia GTX 970 dengan memori video 4 GB atau lebih tinggi. Jika Anda hanya ingin menjalankan BERT di peramban (Anda bahkan tidak memerlukan GPU di komputer Anda untuk ini), kemudian buka bagian Google Colab.
Pertama instal TensorFlow, jika Anda belum memilikinya, ikuti instruksi dari https://www.tensorflow.org/install . Untuk mendukung GPU, Anda harus terlebih dahulu menginstal CUDA Toolkit 9.0, lalu cuDNN SDK 7.2, dan hanya kemudian TensorFlow dengan dukungan GPU:
pip install tensorflow-gpu
Pada dasarnya, ini cukup untuk menjalankan BERT. Tetapi tidak ada instruksi seperti itu, Anda dapat menulis sendiri dengan menyortir sumber dalam file run_classifier.py (situasi yang biasa dalam Machine Learning adalah ketika Anda harus pergi ke sumber bukan dokumentasi). Tetapi kita akan melakukannya dengan lebih mudah dan menggunakan shell BERT Keras (ini juga dapat berguna untuk fine-tuning jaringan nanti, karena menyediakan antarmuka Keras yang nyaman).
Untuk melakukan ini, instal Keras itu sendiri:
pip install keras
Dan setelah Keras BERT:
pip install keras-bert
Kita juga memerlukan file tokenization.py dari BERT github yang asli. Klik tombol Raw dan simpan ke folder dengan skrip yang akan datang, atau unduh seluruh repositori dan ambil file dari sana, atau ambil salinan dari repositori dengan kode ini https://github.com/blade1780/bert .
Sekarang saatnya untuk mengunduh jaringan saraf pra-terlatih. Ada beberapa opsi untuk BERT, semuanya terdaftar di halaman resmi github.com/google-research/bert . Kami akan mengambil multibahasa universal "BERT-Base, Multilingual Cased", untuk 104 bahasa. Unduh multi_cased_L-12_H-768_A-12.zip file (632 Mb) dan unzip ke folder dengan skrip yang akan datang.
Semuanya siap, buat file BERT.py, maka akan ada sedikit kode.
Impor pustaka yang diperlukan dan setel jalur
Karena kita harus menerjemahkan garis teks biasa ke dalam format token khusus, kita akan membuat objek khusus untuk ini. Perhatikan do_lower_case = Salah, karena kami menggunakan model Cased BERT, yang peka terhadap huruf besar-kecil.
tokenizer = tokenization.FullTokenizer(vocab_file=vocab_path, do_lower_case=False)
Memuat model
model = load_trained_model_from_checkpoint(config_path, checkpoint_path, training=True) model.summary()
BERT dapat bekerja dalam dua mode: menebak kata yang terlewat dalam frasa, atau menebak apakah frasa kedua masuk akal setelah yang pertama. Kami akan melakukan kedua opsi.
Untuk mode pertama, Anda perlu mengirimkan frasa dalam format:
[CLS] [MASK] [MASK]. [SEP]
Jaringan saraf seharusnya mengembalikan kalimat lengkap dengan kata-kata yang terisi sebagai ganti topeng: "Saya datang ke toko dan membeli susu."
Untuk mode kedua, kedua frasa yang dipisahkan oleh pemisah harus diumpankan ke input jaringan saraf:
[CLS] . [SEP] . [SEP]
Jaringan saraf harus menjawab apakah frasa kedua merupakan kelanjutan logis dari frasa pertama. Atau apakah itu frase acak yang tidak ada hubungannya dengan yang pertama.
Agar BERT berfungsi, Anda harus menyiapkan tiga vektor, masing-masing dengan panjang 512 angka: token_input, seg_input, dan mask_input.
Token_input akan menyimpan kode sumber kami yang diterjemahkan ke dalam token menggunakan tokenizer. Frasa dalam bentuk indeks dalam kamus akan berada di awal vektor ini, dan sisanya akan diisi dengan nol.
Dalam mask_input, kita harus meletakkan 1 untuk semua posisi di mana topeng [MASK] berada, dan isi sisanya dengan nol.
Dalam seg_input, kita harus menunjukkan frasa pertama (termasuk CLS awal dan pemisah SEP) sebagai 0, frasa kedua (termasuk SEP akhir) sebagai 1, dan mengisi sisanya ke ujung vektor dengan nol.
BERT tidak menggunakan kamus seluruh kata, tetapi lebih dari suku kata yang paling umum. Meskipun juga memiliki kata-kata utuh. Anda dapat membuka file vocab.txt di jaringan saraf yang diunduh dan melihat kata-kata apa yang digunakan jaringan saraf pada inputnya. Ada banyak kata seperti Prancis. Tetapi sebagian besar kata-kata Rusia perlu dipecah menjadi suku kata. Jadi, kata "datang" harus dipecah menjadi "dengan" dan "## pergi". Untuk membantu mengonversi baris teks biasa ke format yang diperlukan oleh BERT, kami menggunakan modul tokenization.py.
Mode 1: Prediksi Kata-Kata Ditutup oleh Token [MASK] dalam Frasa
Frasa input yang diumpankan ke input jaringan saraf
sentence = ' [MASK] [MASK].' print(sentence)
Konversikan ke token. Masalahnya adalah tokenizer tidak dapat memproses tanda layanan seperti [CLS] dan [MASK], meskipun vocab.txt memasukkannya ke dalam kamus. Oleh karena itu, kita harus mematahkan baris kita secara manual dengan spidol [MASK] dan memilih potongan teks biasa dari sana untuk mengubahnya menjadi token BERT menggunakan tokenizer. Tambahkan juga [CLS] di awal dan [SEP] di akhir frasa.
sentence = sentence.replace(' [MASK] ','[MASK]'); sentence = sentence.replace('[MASK] ','[MASK]'); sentence = sentence.replace(' [MASK]','[MASK]')
Token sekarang memiliki token yang dijamin akan dikonversi menjadi indeks dalam kamus. Mari kita lakukan:
token_input = tokenizer.convert_tokens_to_ids(tokens)
Sekarang di token_input ada serangkaian angka (nomor kata dalam kamus vocab.txt) yang perlu dimasukkan ke input jaringan saraf. Tetap hanya untuk memperpanjang vektor ini ke panjang 512 elemen. Konstruksi Python [0] * panjang menciptakan array dengan panjang, diisi dengan nol. Cukup tambahkan ke token kami, yang dengan python menggabungkan dua array menjadi satu.
token_input = token_input + [0] * (512 - len(token_input))
Sekarang buat topeng mask dengan panjang 512, menempatkan 1 di mana-mana, di mana angka 103 muncul di token (yang sesuai dengan penanda [MASK] dalam kamus vocab.txt), dan mengisi sisanya dengan 0:
mask_input = [0]*512 for i in range(len(mask_input)): if token_input[i] == 103: mask_input[i] = 1
Untuk mode operasi BERT pertama, seg_input harus sepenuhnya diisi dengan nol:
seg_input = [0]*512
Langkah terakhir, Anda perlu mengubah array python menjadi array numpy dengan bentuk (1.512), yang kami letakkan dalam subarray []:
token_input = np.asarray([token_input]) mask_input = np.asarray([mask_input]) seg_input = np.asarray([seg_input])
Oke, sudah selesai. Sekarang jalankan prediksi jaringan saraf!
predicts = model.predict([token_input, seg_input, mask_input])[0] predicts = np.argmax(predicts, axis=-1) predicts = predicts[0][:len(tokens)]
Sekarang format hasil dari token kembali ke string yang dipisahkan oleh spasi
out = []
Dan output hasilnya:
print('Result:', out)
Dalam contoh kami, untuk frasa "Saya datang ke [MASK] dan membeli [MASK]." jaringan saraf menghasilkan "rumah" dan "itu": "Saya datang ke rumah dan membelinya." Yah, tidak terlalu buruk untuk pertama kalinya. Membeli rumah pasti lebih baik daripada susu).
Contoh lain (saya tidak memberikan yang gagal, ada lebih dari yang sukses. Dalam kebanyakan kasus, jaringan memberikan jawaban kosong):Bumi adalah [MASKER] ketiga dari Matahari
Hasil: Bintang
sandwich terbaik [MASK] dengan mentega
Hasil: Bertemu
setelah [MASKER] makan siang seharusnya tidur
Hasil: dari ini
menjauh dari [MASKER]
Hasil: ## oh - apakah itu semacam kutukan? )
[MASKER] dari pintu
Hasil: tampilan
Dengan [MASKER] palu dan paku bisa membuat lemari
Hasil: bantuan
Dan jika besok tidak? Hari ini, misalnya, ini bukan [MASK]!
Hasil: akan
Bagaimana Anda bisa bosan mengabaikan [MASK]?
Hasil: dia
Ada logika sehari-hari, ada logika wanita, tetapi tidak ada yang diketahui tentang laki-laki [MASK]
Hasil: Filsafat
Pada wanita, pada usia tiga puluh, gambar pangeran terbentuk, yang cocok dengan [MASK].
Hasil: man
Dengan suara mayoritas, Putri Salju dan tujuh Kurcaci memilih [MASK], dengan satu suara menentang.
Hasil: desa - huruf pertama sudah benar
Nilai kebosanan Anda pada skala 10 poin: [MASK] poin
Hasil: 10
[MASKER] Anda, [MASKER] dan [MASKER]!
Hasil: mencintaiku aku - tidak, BERT, aku tidak bersungguh-sungguh sama sekali
Anda dapat memasukkan frasa bahasa Inggris (dan apa saja dalam 104 bahasa, daftar yang ada di sini )
[MASK] harus terus!
Hasil: I
Mode 2: memeriksa konsistensi dua frasa
Kami menetapkan dua frasa berurutan yang akan dimasukkan ke input jaringan saraf
sentence_1 = ' .' sentence_2 = ' .' print(sentence_1, '->', sentence_2)
Kami akan membuat token dalam format [CLS] phrase_1 [SEP] phrase_2 [SEP], mengonversi teks biasa menjadi token menggunakan tokenizer:
tokens_sen_1 = tokenizer.tokenize(sentence_1) tokens_sen_2 = tokenizer.tokenize(sentence_2) tokens = ['[CLS]'] + tokens_sen_1 + ['[SEP]'] + tokens_sen_2 + ['[SEP]']
Kami mengonversi token string ke indeks numerik (angka kata dalam kamus vocab.txt) dan memperluas vektor ke 512:
token_input = tokenizer.convert_tokens_to_ids(tokens) token_input = token_input + [0] * (512 - len(token_input))
Topeng kata dalam kasus ini sepenuhnya diisi dengan nol
mask_input = [0] * 512
Tetapi topeng proposal harus diisi di bawah frase kedua (termasuk SEP akhir) dengan unit, dan segala sesuatu yang lain dengan nol:
seg_input = [0]*512 len_1 = len(tokens_sen_1) + 2
Kami melewati frasa melalui jaringan saraf (kali ini hasilnya di [1], dan tidak di [0], seperti di atas)
predicts = model.predict([token_input, seg_input, mask_input])[1]
Dan kami memperoleh probabilitas bahwa frasa kedua adalah normal, dan bukan kumpulan kata-kata acak
print('Sentence is okey:', int(round(predicts[0][0]*100)), '%')
Ke dalam dua frasa:
Saya datang ke toko. -> Dan membeli susu.
Respon jaringan saraf:
Kalimat okey: 99%
Dan jika frasa kedua adalah "Crucian sky Pluto", maka jawabannya adalah:
Kalimat okey: 4%
Google colab
Google menyediakan GPU server Tesla K80 gratis dengan memori video 12 Gb (TPU kini tersedia, tetapi konfigurasinya sedikit lebih rumit). Semua kode untuk Colab harus dirancang sebagai notebook jupyter. Untuk meluncurkan BERT di browser, cukup buka tautan
http://colab.research.google.com/github/blade1780/bert/blob/master/BERT.ipynb
Dari menu Runtime , pilih Run All , sehingga untuk pertama kalinya semua sel memulai, unduhan model dan pustaka yang diperlukan terhubung. Setuju untuk mengatur ulang semua Runtime jika perlu.
Jika ada yang salah ...Pastikan GPU dan Python 3 dipilih di menu Runtime -> Change runtime type
Jika tombol hubungkan tidak aktif, klik untuk terhubung.
Sekarang ubah kalimat baris input, kalimat_1 dan kalimat_2 , dan klik ikon Putar di sebelah kiri untuk memulai hanya sel saat ini. Menjalankan seluruh notebook tidak lagi diperlukan.
Anda dapat menjalankan BERT di Google Colab bahkan dari smartphone, tetapi jika itu tidak terbuka, Anda mungkin perlu mengaktifkan kotak centang Versi lengkap di pengaturan browser Anda.
Apa selanjutnya
Untuk melatih BERT untuk tugas tertentu, Anda perlu menambahkan satu atau dua lapisan jaringan Feed Forward yang sederhana di atasnya, dan hanya latihlah tanpa menyentuh jaringan BERT utama. Ini dapat dilakukan pada TensorFlow telanjang atau melalui shell Keras BERT. Pelatihan tambahan semacam itu untuk domain tertentu terjadi dengan sangat cepat dan sangat mirip dengan Fine Tuning di jaringan konvolusi. Jadi, untuk tugas SQuAD, Anda dapat melatih jaringan saraf pada satu TPU hanya dalam 30 menit (dibandingkan dengan 4 hari pada 16 TPU untuk melatih BERT itu sendiri).
Untuk melakukan ini, Anda harus mempelajari bagaimana lapisan terakhir diwakili dalam BERT, dan juga memiliki dataset yang sesuai. Pada halaman BERT resmi https://github.com/google-research/bert ada beberapa contoh untuk tugas yang berbeda, serta instruksi tentang cara memulai pelatihan ulang pada cloud TPUs. Dan yang lainnya harus mencari di sumber di file run_classifier.py dan extract_features.py .
PS
Kode dan notebook jupyter untuk Google Colab yang disajikan di sini dihosting di repositori .
Mukjizat seharusnya tidak diharapkan. Jangan berharap BERT berbicara seperti orang lain. Status state-of-the-art sama sekali tidak berarti bahwa kemajuan dalam NLP telah mencapai tingkat yang dapat diterima. Ini hanya berarti bahwa BERT lebih baik daripada model sebelumnya, yang bahkan lebih buruk. AI percakapan yang kuat masih sangat jauh. Selain itu, BERT terutama merupakan model bahasa, bukan bot obrolan yang sudah jadi, sehingga menunjukkan hasil yang baik hanya setelah pelatihan ulang untuk tugas tertentu.