Pytorch
TensorFlow

#
Tokenizers

Tokenizer adalah salah satu komponen inti dalam pipeline NLP. Tujuan utamanya adalah menerjemahkan teks menjadi data yang dapat diproses oleh model. Karena model hanya dapat memproses angka, tokenizer perlu mengubah input teks kita menjadi data numerik. Di bagian ini, kita akan menjelajahi secara detail apa yang terjadi dalam proses tokenisasi.

Dalam tugas NLP, data yang biasanya diproses adalah teks mentah. Berikut adalah contoh teks seperti itu:

    Jim Henson was a puppeteer

Namun, karena model hanya dapat memproses angka, kita perlu cara untuk mengonversi teks mentah menjadi angka. Itulah tugas tokenizer, dan ada banyak cara untuk melakukannya. Tujuannya adalah menemukan representasi yang paling bermakna — yaitu, yang paling mudah dipahami oleh model — dan, jika memungkinkan, representasi yang paling ringkas.

Mari kita lihat beberapa contoh algoritma tokenisasi dan mencoba menjawab beberapa pertanyaan umum terkait tokenisasi.

##
Berbasis Kata

Jenis tokenizer pertama yang terlintas biasanya adalah berbasis kata. Ini umumnya sangat mudah untuk diatur dan digunakan hanya dengan beberapa aturan, dan sering kali memberikan hasil yang cukup baik. Misalnya, dalam gambar di bawah ini, tujuannya adalah membagi teks mentah menjadi kata-kata dan menemukan representasi numerik untuk masing-masing:

Ada berbagai cara untuk memisahkan teks. Misalnya, kita bisa menggunakan spasi untuk membagi teks menjadi kata-kata dengan fungsi `split()` di Python:

    tokenized_text = "Jim Henson was a puppeteer".split()
    print(tokenized_text)

    ['Jim', 'Henson', 'was', 'a', 'puppeteer']

Ada juga variasi tokenizer berbasis kata yang memiliki aturan tambahan untuk tanda baca. Dengan jenis tokenizer ini, kita bisa memiliki “kosa kata” yang cukup besar, di mana kosa kata didefinisikan sebagai jumlah total token independen dalam korpus kita.

Setiap kata diberi ID, mulai dari 0 hingga ukuran kosa kata. Model menggunakan ID ini untuk mengidentifikasi setiap kata.

Jika kita ingin mencakup seluruh bahasa dengan tokenizer berbasis kata, kita perlu memiliki pengenal untuk setiap kata dalam bahasa tersebut, yang akan menghasilkan jumlah token yang sangat besar. Misalnya, ada lebih dari 500.000 kata dalam bahasa Inggris, jadi untuk membangun peta dari setiap kata ke ID input, kita harus menyimpan sebanyak itu ID. Selain itu, kata seperti “dog” akan direpresentasikan secara berbeda dengan “dogs”, dan model awalnya tidak akan tahu bahwa “dog” dan “dogs” serupa: model akan menganggap keduanya sebagai kata yang tidak berhubungan. Hal yang sama berlaku untuk kata-kata lain seperti “run” dan “running”.

Akhirnya, kita memerlukan token khusus untuk mewakili kata-kata yang tidak ada dalam kosa kata. Ini dikenal sebagai token “unknown” atau tidak dikenal, sering kali ditulis sebagai ”[UNK]” atau ”<unk>”. Ini umumnya merupakan pertanda buruk jika tokenizer menghasilkan banyak token ini, karena berarti tidak dapat menemukan representasi yang masuk akal dari sebuah kata, dan kita kehilangan informasi dalam prosesnya. Tujuannya adalah membuat kosa kata sedemikian rupa sehingga tokenizer menghasilkan sesedikit mungkin token tak dikenal.

Salah satu cara untuk mengurangi jumlah token tak dikenal adalah dengan menggunakan tokenizer berbasis karakter.

##
Berbasis Karakter

Tokenizer berbasis karakter membagi teks menjadi karakter, bukan kata. Ini memiliki dua keuntungan utama:

- Kosa kata jauh lebih kecil.
- Jauh lebih sedikit token tidak dikenal, karena setiap kata dapat dibentuk dari karakter-karakter.

Namun, pendekatan ini juga menimbulkan pertanyaan seputar spasi dan tanda baca:

Pendekatan ini juga tidak sempurna. Karena representasi kini berbasis karakter, bisa dibilang representasinya kurang bermakna: setiap karakter tidak terlalu berarti jika dibandingkan dengan kata. Namun ini juga tergantung bahasa; misalnya, dalam bahasa Tionghoa, setiap karakter membawa lebih banyak informasi dibandingkan karakter dalam bahasa Latin.

Hal lain yang perlu dipertimbangkan adalah bahwa kita akan memiliki jumlah token yang jauh lebih besar untuk diproses oleh model: sementara satu kata mungkin hanya satu token dalam tokenizer berbasis kata, kata itu bisa menjadi 10 atau lebih token ketika diubah menjadi karakter.

Untuk mendapatkan kelebihan dari keduanya, kita bisa menggunakan teknik ketiga yang menggabungkan pendekatan kata dan karakter: tokenisasi subword.

##
Tokenisasi Subword

Algoritma tokenisasi subword didasarkan pada prinsip bahwa kata-kata yang sering digunakan sebaiknya tidak dipecah, sementara kata-kata yang jarang digunakan dapat dipecah menjadi bagian subword yang bermakna.

Misalnya, “annoyingly” mungkin dianggap sebagai kata yang jarang dan dapat dipecah menjadi “annoying” dan “ly”. Kedua bagian ini kemungkinan lebih sering muncul secara terpisah sebagai subword, sementara makna “annoyingly” tetap dipertahankan melalui makna gabungan dari keduanya.

Berikut adalah contoh bagaimana algoritma tokenisasi subword memproses kalimat “Let’s do tokenization!“:

Subword ini membawa makna semantik yang kuat: misalnya, “tokenization” dipecah menjadi “token” dan “ization”, dua token yang bermakna secara semantik sekaligus efisien dalam penggunaan ruang (hanya dua token diperlukan untuk mewakili satu kata panjang). Ini memungkinkan cakupan yang baik dengan kosa kata kecil, dan hampir tidak ada token tak dikenal.

Pendekatan ini sangat berguna untuk bahasa aglutinatif seperti bahasa Turki, di mana kita bisa membentuk kata yang sangat panjang dan kompleks dengan menggabungkan subword.

###
Dan Lainnya!

Tidak mengherankan, ada banyak teknik lain di luar sana. Beberapa di antaranya:

- Byte-level BPE, digunakan dalam GPT-2
- WordPiece, digunakan dalam BERT
- SentencePiece atau Unigram, digunakan dalam berbagai model multibahasa

Sekarang Anda sudah memiliki cukup pemahaman tentang bagaimana tokenizer bekerja untuk mulai menggunakan API-nya.

##
Memuat dan Menyimpan

Memuat dan menyimpan tokenizer semudah memuat dan menyimpan model. Bahkan, menggunakan dua metode yang sama: `from_pretrained()` dan `save_pretrained()`. Metode ini akan memuat atau menyimpan algoritma yang digunakan oleh tokenizer (mirip seperti arsitektur model) serta kosa katanya (mirip seperti bobot model).

Memuat tokenizer BERT yang dilatih dengan checkpoint yang sama seperti BERT dilakukan dengan cara yang sama, hanya saja menggunakan kelas `BertTokenizer`:

    from transformers import BertTokenizer

    tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

Mirip dengan `AutoModel`, kelas `AutoTokenizer` akan secara otomatis memilih kelas tokenizer yang sesuai berdasarkan nama checkpoint, dan dapat langsung digunakan:

    from transformers import AutoTokenizer

    tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

Sekarang kita bisa menggunakan tokenizer seperti yang ditunjukkan sebelumnya:

    tokenizer("Using a Transformer network is simple")

    {'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],
     'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
     'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

Menyimpan tokenizer dilakukan dengan cara yang sama seperti menyimpan model:

    tokenizer.save_pretrained("directory_on_my_computer")

Kita akan membahas lebih lanjut tentang `token_type_ids` di Chapter 3, dan menjelaskan kunci `attention_mask` nanti. Sekarang, mari kita lihat bagaimana `input_ids` dihasilkan. Untuk itu, kita perlu melihat metode-metode intermediate pada tokenizer.

##
Encoding

Menerjemahkan teks menjadi angka disebut encoding. Encoding dilakukan dalam dua tahap: tokenisasi, lalu konversi menjadi ID input.

Seperti yang sudah kita lihat, tahap pertama adalah memecah teks menjadi kata (atau bagian kata, simbol tanda baca, dll.), biasanya disebut token. Ada banyak aturan yang dapat digunakan dalam proses ini, itulah sebabnya kita perlu menginstansiasi tokenizer berdasarkan nama model, agar kita menggunakan aturan yang sama seperti saat model dilatih.

Tahap kedua adalah mengubah token menjadi angka, agar kita bisa membuat tensor dan memberikannya ke model. Untuk melakukan ini, tokenizer memiliki kosa kata, yang merupakan bagian yang kita unduh saat menggunakan metode `from_pretrained()`. Sekali lagi, kita perlu menggunakan kosa kata yang sama seperti saat model dilatih.

Untuk memahami dua langkah ini dengan lebih baik, mari kita eksplorasi keduanya secara terpisah. Perhatikan bahwa kita akan menggunakan metode yang menjalankan bagian dari pipeline tokenisasi secara terpisah agar bisa melihat hasil intermediate-nya, tapi dalam praktiknya, Anda cukup memanggil tokenizer langsung dengan input Anda (seperti pada bagian 2).

###
Tokenisasi

Proses tokenisasi dilakukan dengan metode `tokenize()` dari tokenizer:

    from transformers import AutoTokenizer

    tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

    sequence = "Using a Transformer network is simple"
    tokens = tokenizer.tokenize(sequence)

    print(tokens)

Output dari metode ini adalah daftar string, atau token:

    ['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']

Tokenizer ini adalah tokenizer subword: ia membagi kata sampai mendapatkan token yang bisa direpresentasikan dalam kosa katanya. Itu terjadi di sini dengan kata `transformer`, yang dipecah menjadi dua token: `transform` dan `##er`.

###
Dari Token ke Input ID

Konversi ke input ID dilakukan oleh metode `convert_tokens_to_ids()`:

    ids = tokenizer.convert_tokens_to_ids(tokens)

    print(ids)

    [7993, 170, 11303, 1200, 2443, 1110, 3014]

Output ini, setelah dikonversi menjadi tensor framework yang sesuai, dapat digunakan sebagai input untuk model seperti yang telah kita lihat sebelumnya.

✏️ Coba Sendiri! Replikasi dua langkah terakhir (tokenisasi dan konversi ke ID input) pada kalimat yang kita gunakan di bagian 2 (“I’ve been waiting for a HuggingFace course my whole life.” dan “I hate this so much!”). Pastikan Anda mendapatkan ID input yang sama seperti sebelumnya!

##
Decoding

Decoding adalah proses sebaliknya: dari indeks kosa kata, kita ingin mendapatkan string kembali. Ini dapat dilakukan dengan metode `decode()` seperti berikut:

    decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
    print(decoded_string)

    'Using a Transformer network is simple'

Perhatikan bahwa metode `decode` tidak hanya mengubah indeks menjadi token, tetapi juga menggabungkan kembali token-token yang merupakan bagian dari kata yang sama untuk menghasilkan kalimat yang dapat dibaca. Perilaku ini akan sangat berguna saat kita menggunakan model yang memprediksi teks baru (baik dari prompt atau untuk masalah sequence-to-sequence seperti terjemahan atau ringkasan).

Sekarang Anda seharusnya sudah memahami operasi dasar yang dapat dilakukan oleh tokenizer: tokenisasi, konversi ke ID, dan mengubah kembali ID menjadi string. Namun, ini baru permulaan. Di bagian berikutnya, kita akan mendorong pendekatan kita ke batasnya dan melihat bagaimana cara mengatasinya.

< > Update on GitHub