Skip to main content

Natural Language Processing: Panduan Machine Learning untuk Pemula #13

· 21 min read
Ucup TopekoX
Ucup TopekoX
TimposuLabs creator

Model machine learning hanya bisa menghitung angka. Sementara teks berupa rangkaian huruf yang maknanya bergantung pada urutan, konteks, dan bahkan hal yang tidak tertulis.

Seluruh bidang Natural Language Processing pada dasarnya menjawab satu pertanyaan: bagaimana mengubah teks menjadi angka tanpa kehilangan maknanya?

Artikel ini mengikuti perjalanan jawaban atas pertanyaan itu, dari cara paling sederhana yang masih sangat berguna sampai teknologi di balik ChatGPT. Semua contoh memakai bahasa Indonesia, karena penanganan bahasa Indonesia punya tantangan tersendiri.

Daftar Isi

  1. Kenapa Teks Berbeda dari Data Tabel
  2. Istilah Dasar yang Perlu Dipahami
  3. Menyiapkan Data Contoh
  4. Membersihkan Teks
  5. Tokenisasi
  6. Bag of Words
  7. TF-IDF
  8. Word Embedding
  9. Transformer
  10. Ekosistem Hugging Face
  11. Memilih Pendekatan yang Tepat
  12. Kesalahan Pemula yang Sering Terjadi

Kenapa Teks Berbeda dari Data Tabel

Masalah Utamanya

Pada data tabel, kolom umur berisi angka 35 yang bisa langsung dihitung. Pada teks, kalimat "barangnya bagus banget" tidak punya angka sama sekali.

Anda harus mengubahnya dulu. Dan cara mengubahnya menentukan seberapa banyak makna yang bertahan.

Empat Tantangan Khusus Bahasa

Urutan itu penting. "Anjing menggigit orang" dan "orang menggigit anjing" memakai kata yang sama persis, tapi maknanya berbeda jauh.

Satu kata bisa banyak makna. Kata "bisa" pada "saya bisa berenang" dan "bisa ular" adalah dua hal berbeda.

Panjangnya berbeda-beda. Satu ulasan berisi 5 kata, ulasan lain 500 kata. Model butuh masukan berukuran tetap.

Bahasa Indonesia punya imbuhan yang rumit. Kata "makan", "memakan", "dimakan", "termakan", dan "makanan" berasal dari akar yang sama, tapi bagi komputer semuanya kata berbeda.

Peta Perjalanan

Artikel ini bergerak dari yang paling sederhana ke yang paling modern.

PendekatanIdenyaTahun populer
Bag of WordsHitung kemunculan kata1990-an
TF-IDFBeri bobot berdasarkan kelangkaan kata1990-an sampai sekarang
Word EmbeddingKata menjadi vektor bermakna2013
TransformerVektor yang bergantung konteks kalimat2018 sampai sekarang

Yang menarik, pendekatan lama tidak menjadi usang. TF-IDF masih menjadi pilihan terbaik untuk banyak kasus nyata karena cepat, murah, dan hasilnya bisa dijelaskan.

Istilah Dasar yang Perlu Dipahami

Korpus adalah kumpulan seluruh teks yang Anda punya. Kalau Anda punya 10.000 ulasan produk, itulah korpus Anda.

Dokumen adalah satu satuan teks. Bisa satu ulasan, satu artikel, atau satu pesan.

Token adalah potongan terkecil hasil pemotongan teks. Biasanya satu kata, tapi bisa juga potongan kata.

Vocabulary adalah daftar semua token unik yang ada di korpus Anda.

Vektorisasi adalah proses mengubah teks menjadi deretan angka.

Corpus, dokumen, token sering tertukar. Ingat urutannya: korpus berisi banyak dokumen, dokumen berisi banyak token.

Menyiapkan Data Contoh

Kita akan membuat kumpulan ulasan produk berbahasa Indonesia beserta label sentimennya.

import numpy as np
import pandas as pd

np.random.seed(42)

positif_awal = ["Barangnya bagus", "Produk mantap", "Kualitas oke",
"Sangat memuaskan", "Pengiriman cepat", "Recommended banget"]
positif_akhir = ["sesuai deskripsi", "harga terjangkau", "packing rapi",
"penjual ramah", "bakal beli lagi", "worth it"]

negatif_awal = ["Barangnya jelek", "Produk mengecewakan", "Kualitas buruk",
"Sangat kecewa", "Pengiriman lama", "Tidak recommended"]
negatif_akhir = ["tidak sesuai deskripsi", "harga kemahalan", "packing rusak",
"penjual tidak responsif", "kapok beli di sini", "buang buang uang"]

ulasan, label = [], []
for _ in range(400):
a, b = np.random.choice(positif_awal), np.random.choice(positif_akhir)
ulasan.append(f"{a}, {b}."); label.append(1)

a, b = np.random.choice(negatif_awal), np.random.choice(negatif_akhir)
ulasan.append(f"{a}, {b}."); label.append(0)

df = pd.DataFrame({"teks": ulasan, "sentimen": label})
df = df.sample(frac=1, random_state=42).reset_index(drop=True)

print(df.head(8))
print("\nJumlah data:", len(df))
print("Proporsi positif:", df["sentimen"].mean())

Membersihkan Teks

Kenapa Perlu Dibersihkan

Bagi komputer, "Bagus", "bagus", dan "bagus!" adalah tiga hal berbeda. Pembersihan menyeragamkan hal-hal semacam itu supaya sinyalnya tidak terpecah.

Menyeragamkan Huruf Besar Kecil

teks = "Barangnya BAGUS Banget!"
print(teks.lower())

Ini langkah paling dasar dan hampir selalu dilakukan. Pengecualiannya adalah kalau huruf kapital membawa makna, misalnya untuk mendeteksi nama orang atau tempat.

Membersihkan Karakter Pengganggu

import re

def bersihkan(teks):
teks = teks.lower()
teks = re.sub(r"http\S+|www\.\S+", " ", teks) # buang tautan
teks = re.sub(r"@\w+", " ", teks) # buang mention
teks = re.sub(r"[^a-z\s]", " ", teks) # sisakan huruf saja
teks = re.sub(r"\s+", " ", teks).strip() # rapikan spasi
return teks

contoh = "Barangnya BAGUS banget!!! Cek di http://toko.com @adminstore 100% puas"
print("Sebelum:", contoh)
print("Sesudah:", bersihkan(contoh))

Hati-hati Membuang Angka

Pada contoh di atas angka ikut terbuang. Untuk analisis sentimen itu biasanya tidak masalah. Tapi kalau Anda menganalisis ulasan yang menyebut "garansi 2 tahun" atau "diskon 50%", angka itu justru penting.

Selalu sesuaikan pembersihan dengan tujuannya, jangan asal menyalin fungsi dari internet.

Stopwords

Stopwords adalah kata yang sangat sering muncul tapi biasanya tidak membawa makna khusus. Dalam bahasa Indonesia contohnya "yang", "di", "dan", "ini", "itu".

stopwords_id = {"yang", "di", "ke", "dari", "dan", "atau", "ini", "itu",
"adalah", "untuk", "dengan", "pada", "ada", "juga", "saya",
"aku", "kamu", "dia", "kami", "mereka", "akan", "sudah"}

def buang_stopwords(teks, daftar):
return " ".join([k for k in teks.split() if k not in daftar])

kalimat = "produk ini adalah yang paling bagus di antara semua"
print("Sebelum:", kalimat)
print("Sesudah:", buang_stopwords(kalimat, stopwords_id))

Kapan Stopwords Jangan Dibuang

Ini penting dan sering diabaikan.

Untuk analisis sentimen, kata "tidak" sangat menentukan. Kalau ikut terbuang, "tidak bagus" berubah menjadi "bagus" dan maknanya terbalik.

stopwords_berbahaya = {"tidak", "bukan", "jangan", "kurang", "belum", "tanpa"}
kalimat = "produk ini tidak bagus dan tidak sesuai"
print("Kalau 'tidak' dibuang:", buang_stopwords(kalimat, {"tidak", "ini", "dan"}))

Aturan praktisnya: untuk analisis sentimen, pertahankan kata negasi. Untuk pengelompokan topik, membuang stopwords biasanya aman.

Bahkan lebih jauh lagi, dengan model modern seperti transformer, membuang stopwords justru merugikan karena modelnya memang dirancang memahami struktur kalimat lengkap.

Stemming untuk Bahasa Indonesia

Stemming memotong imbuhan untuk mendapatkan kata dasar. Ini penting untuk bahasa Indonesia yang imbuhannya kaya.

# pip install Sastrawi
from Sastrawi.Stemmer.StemmerFactory import StemmerFactory

stemmer = StemmerFactory().create_stemmer()

contoh_kata = ["memakan", "dimakan", "makanan", "termakan",
"mengecewakan", "kekecewaan", "pengiriman", "dikirimkan"]

for kata in contoh_kata:
print(f"{kata:15s} -> {stemmer.stem(kata)}")

Sastrawi adalah pustaka stemming khusus bahasa Indonesia. Tanpa ini, "mengecewakan" dan "kekecewaan" dianggap dua kata yang sama sekali tidak berhubungan.

Kapan Stemming Membantu

Membantu kalau kosakata Anda besar dan data latih terbatas, karena menggabungkan variasi kata mengurangi jumlah kolom fitur.

Kurang membantu, bahkan merugikan, kalau memakai model transformer. Model itu sudah dilatih memahami bentuk kata utuh.

Peringatan: Jangan Berlebihan Membersihkan

Ini kesalahan umum pemula. Pembersihan yang terlalu agresif membuang informasi.

Tanda seru berulang bisa menandakan emosi kuat. Emoji sering membawa sentimen jelas. Huruf kapital semua bisa berarti berteriak.

Aturan praktisnya: bersihkan seperlunya, lalu uji apakah pembersihan itu benar-benar menaikkan skor. Kalau tidak, jangan lakukan.

Tokenisasi

Apa Itu Tokenisasi

Tokenisasi adalah memotong teks menjadi bagian-bagian kecil.

kalimat = "barangnya bagus dan pengirimannya cepat"

# Cara paling sederhana: pisah berdasarkan spasi
print(kalimat.split())

Masalah dengan Pemisahan Berdasarkan Spasi

Cara ini terlihat mudah, tapi punya beberapa masalah.

Kata yang tidak dikenal. Kalau ada kata yang tidak pernah muncul di data latih, model tidak tahu harus berbuat apa. Bahasa gaul, salah ketik, dan istilah baru selalu bermunculan.

Kosakata membengkak. "makan", "makanan", "memakan", "dimakan" jadi empat entri terpisah.

Bahasa Indonesia informal. Di media sosial ada "gk", "ga", "nggak", "engga", "kaga" yang semuanya berarti "tidak".

Tokenisasi Subword

Model modern memakai pendekatan berbeda: memotong kata menjadi potongan yang lebih kecil.

Contohnya, kata "pengiriman" bisa dipotong menjadi ["peng", "##irim", "##an"].

Kenapa Ini Lebih Baik

Tidak ada kata yang benar-benar asing. Kata baru apa pun bisa disusun dari potongan yang sudah dikenal.

Kosakata tetap kecil. Biasanya sekitar 30.000 potongan sudah cukup untuk menangani bahasa apa pun.

Hubungan antar kata terjaga. "pengiriman" dan "dikirimkan" berbagi potongan yang sama.

# pip install transformers
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("indobenchmark/indobert-base-p1")

kalimat = "pengirimannya sangat mengecewakan"
token = tokenizer.tokenize(kalimat)
print("Token:", token)
print("ID angka:", tokenizer.encode(kalimat))

Perhatikan tanda ## pada beberapa token. Itu menandakan potongan tersebut adalah lanjutan dari kata sebelumnya, bukan kata baru.

Kode ini butuh koneksi internet saat pertama dijalankan, karena modelnya diunduh dulu. Setelah itu tersimpan di komputer Anda.

Bag of Words

Idenya

Bayangkan tiap dokumen dimasukkan ke dalam kantong, lalu semua katanya dituang keluar dan dihitung. Urutannya hilang, yang tersisa hanya berapa kali tiap kata muncul.

Itulah kenapa namanya "kantong kata".

Contoh Kecil

from sklearn.feature_extraction.text import CountVectorizer

dokumen = [
"barangnya bagus pengiriman cepat",
"barangnya jelek pengiriman lama",
"bagus bagus sangat bagus",
]

cv = CountVectorizer()
matriks = cv.fit_transform(dokumen)

hasil = pd.DataFrame(matriks.toarray(), columns=cv.get_feature_names_out())
print(hasil)

Tiap baris adalah satu dokumen, tiap kolom adalah satu kata, dan isinya berapa kali kata itu muncul.

Sekarang teks sudah berubah menjadi angka dan bisa dimasukkan ke model machine learning apa pun.

Kelemahannya

Urutan hilang sepenuhnya. "tidak bagus" dan "bagus tidak" menghasilkan angka yang sama persis.

Dimensi sangat besar. Kalau korpus Anda punya 50.000 kata unik, matriksnya punya 50.000 kolom.

Matriks hampir seluruhnya nol. Satu ulasan pendek hanya memakai belasan kata dari 50.000 yang ada. Sisanya nol semua.

Tidak tahu makna. Bagi model, "bagus" dan "mantap" adalah dua kolom yang tidak berhubungan sama sekali.

N-gram: Menyelamatkan Sebagian Urutan

Solusi sebagian untuk masalah urutan adalah menghitung pasangan kata, bukan hanya kata tunggal.

cv2 = CountVectorizer(ngram_range=(1, 2)) # kata tunggal dan pasangan
matriks2 = cv2.fit_transform(["produk ini tidak bagus"])
print(cv2.get_feature_names_out())

Sekarang "tidak bagus" menjadi satu fitur tersendiri, sehingga maknanya bisa dibedakan dari "bagus" saja.

ngram_range=(1, 2) berarti ambil kata tunggal dan pasangan dua kata. Ini pengaturan yang sangat umum dipakai.

Kelemahannya, jumlah fitur meledak. Batasi dengan min_df yang membuang n-gram yang terlalu jarang muncul.

TF-IDF

Masalah yang Diselesaikan

Pada Bag of Words, kata "yang" yang muncul di semua dokumen mendapat angka tinggi, padahal tidak membedakan apa pun.

Sebaliknya, kata "mengecewakan" yang hanya muncul di beberapa dokumen justru sangat informatif, tapi angkanya kecil.

TF-IDF memperbaiki ketimpangan ini.

Cara Kerjanya

Nama TF-IDF berasal dari dua bagian.

TF (Term Frequency) menghitung seberapa sering kata muncul dalam satu dokumen. Makin sering, makin penting untuk dokumen itu.

IDF (Inverse Document Frequency) menghitung seberapa langka kata itu di seluruh korpus. Kata yang muncul di semua dokumen mendapat nilai rendah, kata yang langka mendapat nilai tinggi.

Keduanya dikalikan. Hasilnya: kata yang sering muncul di satu dokumen tapi jarang di dokumen lain mendapat bobot tertinggi. Kata seperti itulah yang paling membedakan.

Melihat Perbedaannya

from sklearn.feature_extraction.text import TfidfVectorizer

dokumen = [
"produk ini bagus sekali",
"produk ini jelas mengecewakan",
"produk ini biasa saja",
]

tfidf = TfidfVectorizer()
hasil = pd.DataFrame(tfidf.fit_transform(dokumen).toarray(),
columns=tfidf.get_feature_names_out()).round(3)
print(hasil)

Perhatikan kolom "produk" dan "ini". Karena muncul di semua dokumen, bobotnya rendah. Kata seperti "mengecewakan" yang hanya muncul sekali mendapat bobot jauh lebih tinggi.

TF-IDF melakukan penyaringan stopwords secara otomatis, tanpa perlu daftar manual.

Membuat Pengklasifikasi Teks Lengkap

from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

X_train, X_test, y_train, y_test = train_test_split(
df["teks"], df["sentimen"], test_size=0.25,
stratify=df["sentimen"], random_state=42
)

model = Pipeline([
("tfidf", TfidfVectorizer(
lowercase=True,
ngram_range=(1, 2), # kata tunggal dan pasangan
min_df=2, # buang kata yang muncul di bawah 2 dokumen
max_df=0.9, # buang kata yang muncul di atas 90% dokumen
sublinear_tf=True, # redam efek pengulangan berlebihan
)),
("model", LogisticRegression(max_iter=2000, class_weight="balanced")),
])

model.fit(X_train, y_train)
print(classification_report(y_test, model.predict(X_test), digits=3))

Argumen yang Perlu Diketahui

min_df=2 membuang kata yang terlalu jarang. Kata yang cuma muncul sekali biasanya salah ketik atau tidak berguna.

max_df=0.9 membuang kata yang muncul di hampir semua dokumen, karena tidak membedakan apa pun.

sublinear_tf=True membuat kata yang muncul 10 kali tidak dianggap 10 kali lebih penting daripada yang muncul sekali. Biasanya menaikkan performa.

Melihat Kata Paling Berpengaruh

Ini keunggulan besar TF-IDF: hasilnya bisa dijelaskan.

nama_fitur = model.named_steps["tfidf"].get_feature_names_out()
bobot = model.named_steps["model"].coef_[0]

skor = pd.Series(bobot, index=nama_fitur).sort_values()

print("Paling menandakan NEGATIF:")
print(skor.head(10).round(3))
print("\nPaling menandakan POSITIF:")
print(skor.tail(10).round(3))

Anda bisa langsung menunjukkan daftar ini ke atasan atau klien. Model transformer tidak bisa memberi penjelasan sesederhana ini.

Mencoba pada Teks Baru

teks_baru = [
"barangnya bagus sekali, pengiriman cepat",
"sangat kecewa, produk rusak dan penjual tidak responsif",
"lumayan lah, sesuai harga",
]

for t in teks_baru:
prob = model.predict_proba([t])[0][1]
label = "POSITIF" if prob > 0.5 else "NEGATIF"
print(f"{label} ({prob:.1%}) : {t}")

Kapan TF-IDF Masih Pilihan Terbaik

Jangan mengira TF-IDF sudah usang. Ia masih pilihan terbaik kalau:

  • Data latih Anda sedikit, di bawah beberapa ribu dokumen
  • Anda butuh hasil yang bisa dijelaskan
  • Kecepatan penting, karena TF-IDF ribuan kali lebih cepat daripada transformer
  • Anda tidak punya GPU
  • Masalahnya sederhana, misalnya membedakan kategori yang kosakatanya jelas berbeda Selalu jadikan TF-IDF sebagai baseline sebelum mencoba yang lebih rumit.

Word Embedding

Masalah yang Diselesaikan

TF-IDF tidak tahu bahwa "bagus" dan "mantap" punya makna mirip. Bagi TF-IDF, keduanya sekadar dua kolom berbeda yang tidak berhubungan.

Kalau model dilatih dengan ulasan yang memakai kata "bagus", lalu bertemu ulasan yang memakai "mantap", model tidak bisa memindahkan pengetahuannya.

Idenya

Ubah tiap kata menjadi vektor berisi beberapa ratus angka, di mana kata dengan makna mirip punya vektor yang berdekatan.

Ini mengubah kata dari sekadar label menjadi posisi dalam sebuah ruang makna.

Perbedaan dengan Bag of Words

Bag of Words menghasilkan vektor panjang dan hampir seluruhnya nol. Kata "bagus" mungkin jadi [0, 0, ..., 1, ..., 0] dengan 50.000 angka.

Embedding menghasilkan vektor pendek dan padat. Kata "bagus" mungkin jadi [0.23, -0.51, 0.88, ...] dengan 300 angka, dan tiap angka membawa sedikit informasi tentang maknanya.

Sifat yang Menakjubkan

Embedding menangkap hubungan antar kata sebagai operasi matematika.

vektor("raja") - vektor("pria") + vektor("wanita") ≈ vektor("ratu")

Ini bukan diprogram. Sifat itu muncul sendiri dari cara model dilatih.

Bagaimana Model Belajar Makna

Idenya berasal dari satu prinsip: kata dikenali dari teman-temannya.

Kalau kata "mantap" dan "bagus" sering muncul di lingkungan kata yang mirip ("barangnya ___ sekali", "kualitasnya ___"), model menyimpulkan keduanya bermakna serupa.

Model dilatih dengan tugas sederhana: tebak kata yang hilang dari kalimat. Untuk bisa menebak dengan baik, model terpaksa mempelajari makna kata.

Melatih Embedding Sendiri

# pip install gensim
from gensim.models import Word2Vec

kalimat_token = [bersihkan(t).split() for t in df["teks"]]

w2v = Word2Vec(
sentences=kalimat_token,
vector_size=100, # panjang vektor tiap kata
window=5, # berapa kata di kiri dan kanan yang dilihat
min_count=2, # abaikan kata yang muncul kurang dari 2 kali
workers=4,
seed=42,
)

print("Ukuran kosakata:", len(w2v.wv))
print("\nKata mirip dengan 'bagus':")
for kata, skor in w2v.wv.most_similar("bagus", topn=5):
print(f" {kata:15s} {skor:.4f}")

Catatan Penting

Hasil di atas mungkin terlihat aneh karena data contoh kita terlalu sedikit. Word2Vec butuh jutaan kata untuk menghasilkan embedding yang bagus.

Untuk pemakaian nyata, hampir selalu lebih baik memakai embedding yang sudah dilatih orang lain dengan korpus besar, daripada melatih sendiri dari data kecil.

Memakai Embedding untuk Klasifikasi

Cara paling sederhana: rata-ratakan vektor semua kata dalam satu dokumen.

def vektor_dokumen(teks, model):
kata = [k for k in bersihkan(teks).split() if k in model.wv]
if not kata:
return np.zeros(model.vector_size)
return np.mean([model.wv[k] for k in kata], axis=0)

X_vektor = np.array([vektor_dokumen(t, w2v) for t in df["teks"]])
print("Bentuk matriks:", X_vektor.shape)

Sekarang tiap dokumen menjadi satu vektor berisi 100 angka, yang bisa dimasukkan ke model apa pun.

Kelemahan Word2Vec

Satu kata hanya punya satu vektor. Kata "bisa" pada "bisa ular" dan "saya bisa" mendapat vektor yang sama persis, padahal maknanya berbeda.

Urutan tetap hilang kalau vektornya sekadar dirata-ratakan.

Kata baru tetap masalah. Kalau kata tidak ada di kosakata, tidak ada vektornya. FastText memperbaiki ini dengan memakai potongan huruf.

Kelemahan pertama itulah yang diselesaikan transformer.

Transformer

Masalah yang Diselesaikan

Perhatikan dua kalimat ini:

  • "Bank ini memberikan bunga tinggi"
  • "Kami duduk di bank taman" Kata "bank" sama, maknanya berbeda. Word2Vec memberi vektor yang sama untuk keduanya.

Transformer memberi vektor yang berbeda, karena vektornya dihitung dengan melihat seluruh kalimat.

Inilah yang disebut embedding kontekstual, dan ini lompatan besar dalam NLP.

Ide Attention

Mekanisme inti transformer disebut attention, atau perhatian.

Analogi

Bayangkan Anda membaca kalimat: "Andi memberikan buku itu kepada Budi karena dia sudah selesai membacanya."

Untuk memahami kata "dia", otak Anda otomatis menoleh kembali ke kata "Andi". Anda memberi perhatian lebih pada kata itu daripada kata lain.

Attention melakukan hal yang sama. Saat memproses tiap kata, model menghitung seberapa besar perhatian yang harus diberikan pada setiap kata lain dalam kalimat.

Hasilnya, makna tiap kata dihitung dengan mempertimbangkan seluruh konteksnya.

Pre-training dan Fine-tuning

Ini konsep yang membuat transformer sangat praktis.

Pre-training adalah tahap model dilatih dengan teks dalam jumlah sangat besar, misalnya seluruh Wikipedia. Tugasnya sederhana: menebak kata yang disembunyikan. Tahap ini butuh ribuan jam GPU dan sudah dilakukan oleh perusahaan besar.

Fine-tuning adalah tahap Anda mengambil model hasil pre-training itu, lalu melatihnya sedikit lagi dengan data Anda sendiri untuk tugas spesifik. Tahap ini bisa selesai dalam hitungan menit.

Analogi

Pre-training seperti pendidikan umum: model belajar bahasa Indonesia secara luas.

Fine-tuning seperti pelatihan kerja: model diajari tugas khusus, misalnya menilai sentimen ulasan produk.

Anda tidak perlu mengulang pendidikan umumnya. Cukup ambil yang sudah lulus, lalu latih untuk pekerjaan Anda.

Model untuk Bahasa Indonesia

Model berbahasa Inggris tidak bekerja baik untuk teks Indonesia. Untungnya sudah ada beberapa model khusus.

ModelKegunaan
indobenchmark/indobert-base-p1Umum, pilihan pertama untuk bahasa Indonesia
indolem/indobert-base-uncasedAlternatif, dilatih dengan korpus berbeda
cahya/bert-base-indonesian-522MAlternatif lain
firqaaa/indo-sentence-bert-baseKhusus untuk membandingkan kemiripan kalimat

Ekosistem Hugging Face

Apa Itu Hugging Face

Hugging Face adalah tempat komunitas berbagi model NLP siap pakai, beserta pustaka Python untuk menggunakannya.

Tiga bagian yang perlu diketahui:

Model Hub adalah kumpulan lebih dari ratusan ribu model yang bisa diunduh gratis.

Pustaka transformers adalah kode Python untuk memakai model-model itu.

Pustaka datasets adalah kumpulan dataset siap pakai.

Pemasangan

pip install transformers torch

Model akan diunduh otomatis saat pertama kali dipakai, jadi butuh koneksi internet di awal.

Cara Tercepat: Pipeline

pipeline adalah fungsi yang menangani semua langkah sekaligus, dari tokenisasi sampai keluaran akhir.

from transformers import pipeline

# Analisis sentimen dengan model yang sudah jadi
penilai = pipeline("sentiment-analysis",
model="w11wo/indonesian-roberta-base-sentiment-classifier")

teks = [
"barangnya bagus banget, pengiriman cepat",
"sangat kecewa, barang rusak dan penjual tidak responsif",
"biasa saja sih, sesuai harga",
]

for hasil, t in zip(penilai(teks), teks):
print(f"{hasil['label']:8s} ({hasil['score']:.2%}) : {t}")

Tiga baris kode, dan Anda sudah punya pengklasifikasi sentimen yang bagus tanpa melatih apa pun.

Tugas Lain yang Tersedia

# Mengisi kata yang hilang
pengisi = pipeline("fill-mask", model="indobenchmark/indobert-base-p1")
for h in pengisi("Ibu pergi ke [MASK] untuk membeli sayur.")[:3]:
print(f"{h['token_str']:15s} {h['score']:.4f}")

# Menjawab pertanyaan dari sebuah teks
# penjawab = pipeline("question-answering", model="...")

# Meringkas teks
# peringkas = pipeline("summarization", model="...")

# Menerjemahkan
# penerjemah = pipeline("translation", model="...")

Memakai Model untuk Membuat Embedding Kalimat

Ini pemakaian yang sangat berguna: mengubah kalimat menjadi vektor yang menangkap maknanya.

from transformers import AutoTokenizer, AutoModel
import torch

nama_model = "indobenchmark/indobert-base-p1"
tokenizer = AutoTokenizer.from_pretrained(nama_model)
model_bert = AutoModel.from_pretrained(nama_model)

def buat_embedding(daftar_teks):
masukan = tokenizer(daftar_teks, padding=True, truncation=True,
max_length=128, return_tensors="pt")
with torch.no_grad():
keluaran = model_bert(**masukan)

# Rata-ratakan vektor semua token, dengan memperhitungkan padding
topeng = masukan["attention_mask"].unsqueeze(-1).float()
jumlah = (keluaran.last_hidden_state * topeng).sum(1)
return (jumlah / topeng.sum(1)).numpy()

kalimat = [
"barangnya bagus sekali",
"produknya mantap banget", # makna mirip kalimat pertama
"pengiriman sangat lambat", # makna berbeda
]

vektor = buat_embedding(kalimat)
print("Bentuk:", vektor.shape)

from sklearn.metrics.pairwise import cosine_similarity
kemiripan = cosine_similarity(vektor)
print("\nKemiripan antar kalimat:")
print(pd.DataFrame(kemiripan.round(3),
index=["bagus", "mantap", "lambat"],
columns=["bagus", "mantap", "lambat"]))

Perhatikan bahwa kalimat pertama dan kedua punya kemiripan lebih tinggi meski tidak berbagi satu kata pun. Inilah yang tidak bisa dilakukan TF-IDF.

Memakai Embedding untuk Klasifikasi

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

# Ambil sebagian data agar cepat
sampel = df.sample(300, random_state=42)
X_emb = buat_embedding(sampel["teks"].tolist())
y_emb = sampel["sentimen"].values

Xe_tr, Xe_te, ye_tr, ye_te = train_test_split(
X_emb, y_emb, test_size=0.25, stratify=y_emb, random_state=42)

clf = LogisticRegression(max_iter=2000).fit(Xe_tr, ye_tr)
print(classification_report(ye_te, clf.predict(Xe_te), digits=3))

Pendekatan ini sering disebut feature extraction. Model transformer dipakai hanya untuk membuat fitur, lalu model sederhana yang melakukan klasifikasi.

Ini kompromi yang baik: lebih akurat daripada TF-IDF, tapi jauh lebih murah daripada fine-tuning penuh.

Fine-tuning

Kalau Anda punya cukup data dan butuh akurasi maksimal, latih ulang seluruh modelnya.

from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
from datasets import Dataset

data_hf = Dataset.from_pandas(df.rename(columns={"sentimen": "labels"}))
data_hf = data_hf.map(
lambda x: tokenizer(x["teks"], truncation=True, padding="max_length",
max_length=64),
batched=True,
)
data_split = data_hf.train_test_split(test_size=0.2, seed=42)

model_klasifikasi = AutoModelForSequenceClassification.from_pretrained(
nama_model, num_labels=2)

pengaturan = TrainingArguments(
output_dir="./hasil",
num_train_epochs=3,
per_device_train_batch_size=16,
learning_rate=2e-5, # jauh lebih kecil dari biasanya
eval_strategy="epoch",
logging_steps=50,
)

pelatih = Trainer(
model=model_klasifikasi,
args=pengaturan,
train_dataset=data_split["train"],
eval_dataset=data_split["test"],
)

# pelatih.train() # butuh waktu, sebaiknya dijalankan dengan GPU

Catatan Penting untuk Pemula

learning_rate=2e-5 jauh lebih kecil daripada yang biasa dipakai untuk model lain. Ini disengaja: model sudah pintar, Anda hanya ingin menyesuaikannya sedikit, bukan mengubahnya total.

Fine-tuning butuh GPU untuk data berukuran nyata. Tanpa GPU, bisa memakan waktu berjam-jam. Google Colab menyediakan GPU gratis untuk latihan.

Mencari Model di Hub

Kunjungi huggingface.co/models, lalu saring berdasarkan bahasa Indonesia dan jenis tugas.

Sebelum memakai sebuah model, periksa tiga hal: berapa banyak orang mengunduhnya, apakah ada penjelasan cara pakainya, dan apa lisensinya.

Memilih Pendekatan yang Tepat

Tabel Perbandingan

AspekTF-IDFWord EmbeddingTransformer
KecepatanSangat cepatCepatLambat
Butuh GPUTidakTidakSebaiknya ya
Data minimalRatusanRibuanRatusan (dengan fine-tuning)
Paham konteksTidakSebagianYa
Paham sinonimTidakYaYa
Bisa dijelaskanSangat bisaSulitSangat sulit
Ukuran modelKecilSedangBesar (ratusan MB)
Biaya operasionalSangat murahMurahMahal

Urutan yang Disarankan

Langkah 1. Mulai dari TF-IDF dengan regresi logistik. Cepat, dan sering sudah cukup baik.

Langkah 2. Kalau kurang memuaskan, coba pipeline Hugging Face dengan model siap pakai. Tidak perlu melatih apa pun.

Langkah 3. Kalau masih kurang, ekstrak embedding dari transformer lalu latih model sederhana di atasnya.

Langkah 4. Kalau butuh akurasi maksimal dan punya cukup data serta GPU, lakukan fine-tuning.

Jangan langsung melompat ke langkah 4. Banyak masalah nyata sudah selesai di langkah 1.

Pertimbangan Praktis

Model transformer berukuran ratusan megabita dan butuh sumber daya besar. Kalau aplikasi Anda harus merespons dalam milidetik atau berjalan di perangkat kecil, TF-IDF mungkin satu-satunya pilihan yang masuk akal.

Selalu pertimbangkan biaya operasional, bukan hanya skor.

Kesalahan Pemula yang Sering Terjadi

Membuang Kata Negasi pada Analisis Sentimen

Membuang "tidak" mengubah "tidak bagus" menjadi "bagus". Selalu periksa daftar stopwords sebelum memakainya.

Membersihkan Teks Terlalu Agresif

Tanda seru, emoji, dan huruf kapital bisa membawa informasi sentimen. Uji dulu apakah pembersihan benar-benar membantu.

Melakukan Vektorisasi Sebelum Membagi Data

Ini bentuk kebocoran data. Kalau TfidfVectorizer di-fit pada seluruh data, informasi dari data uji ikut masuk. Selalu bungkus dalam Pipeline.

Memakai Model Berbahasa Inggris untuk Teks Indonesia

Hasilnya akan buruk. Cari model yang memang dilatih dengan bahasa Indonesia.

Melatih Word2Vec dari Data Kecil

Embedding butuh jutaan kata untuk menghasilkan makna yang berguna. Untuk data kecil, pakai model yang sudah dilatih orang lain.

Langsung Memakai Transformer Tanpa Baseline

Anda tidak akan tahu apakah kerumitannya sepadan. Buat baseline TF-IDF dulu, selalu.

Melakukan Stemming Sebelum Memakai Transformer

Model transformer sudah dilatih memahami kata utuh beserta imbuhannya. Stemming justru merusak masukannya.

Mengabaikan Panjang Maksimal Token

Model BERT biasanya hanya menerima 512 token. Teks yang lebih panjang akan terpotong diam-diam. Kalau dokumen Anda panjang, potong menjadi beberapa bagian atau pakai model khusus dokumen panjang.

Fine-tuning dengan Learning Rate Terlalu Besar

Learning rate biasa seperti 0,001 akan merusak pengetahuan yang sudah dimiliki model. Untuk fine-tuning, pakai kisaran 2e-5 sampai 5e-5.

Menganggap Skor Tinggi Berarti Model Paham Bahasa

Model bisa mencapai akurasi tinggi hanya dengan menghafal beberapa kata kunci. Selalu uji dengan kalimat yang bentuknya berbeda dari data latih.

Penutup

Perjalanan NLP dari Bag of Words sampai transformer adalah cerita tentang memperbaiki satu masalah pada satu waktu. Bag of Words kehilangan urutan, embedding menambahkan makna, transformer menambahkan konteks.

Tiga hal untuk diingat:

Pertama, TF-IDF belum usang. Untuk banyak masalah nyata, ia masih pilihan terbaik karena cepat, murah, dan bisa dijelaskan. Jadikan selalu sebagai baseline.

Kedua, jangan melatih model dari nol. Ekosistem Hugging Face menyediakan model yang sudah dilatih dengan sumber daya yang tidak mungkin Anda tandingi. Ambil, lalu sesuaikan seperlunya.

Ketiga, untuk bahasa Indonesia, pilih alat yang memang dirancang untuknya. Sastrawi untuk stemming, IndoBERT untuk transformer. Memakai alat berbahasa Inggris pada teks Indonesia adalah penyebab kegagalan yang paling mudah dihindari.