πŸ“ Artikel ini ditulis dalam Bahasa Indonesia
πŸ”₯ Seri Belajar PyTorch Part 5

NLP: Dari Teks ke Sentiment Classifier

Dari gambar ke bahasa! Part 5 mengajarkan bagaimana komputer "membaca" teks: tokenization, word embeddings, LSTM, dan membangun sentiment classifier yang menentukan apakah review film positif atau negatif. Plus: intro ke Transformer dan Hugging Face β€” fondasi ChatGPT & BERT.

πŸ“… Maret 2026 ⏱ 28 menit baca 🏷 PyTorch • NLP • LSTM • Embeddings • Transformers
πŸ“š Seri Belajar PyTorch:
1 2 3 4 5 6 7 8 9 10

πŸ“‘ Daftar Isi β€” Part 5

  1. Dari Pixel ke Kata β€” Perbedaan fundamental CV vs NLP
  2. NLP Pipeline β€” Teks β†’ Token β†’ Angka β†’ Embedding β†’ Model
  3. Tokenization β€” Pecah teks jadi potongan yang bisa dihitung
  4. Word Embeddings β€” Kata sebagai vektor dalam ruang makna
  5. LSTM β€” Network yang "ingat" urutan kata
  6. Kode: Sentiment Classifier β€” Positif atau Negatif?
  7. Transformer & Hugging Face β€” Masa depan NLP
  8. Ringkasan & Preview Part 6
πŸ“

1. Dari Pixel ke Kata

Computer Vision = pixel grid. NLP = urutan kata dengan makna dan konteks.

Di Part 1-4, input model adalah gambar β€” grid 2D angka (pixel) yang bisa langsung dimasukkan ke tensor. Teks sangat berbeda: kata-kata tidak bisa langsung jadi angka, urutannya penting ("anjing mengejar kucing" β‰  "kucing mengejar anjing"), dan panjangnya bervariasi.

πŸ–ΌοΈ Computer Vision

Input: grid pixel (28Γ—28 atau 224Γ—224). Panjang fixed. Spatial structure (2D). Operasi: konvolusi. Model: CNN, ResNet.

πŸ“ NLP

Input: urutan kata (bervariasi panjang). Sequential structure (1D). Konteks dan makna penting. Model: LSTM, Transformer.

πŸ”„

2. NLP Pipeline β€” Teks ke Prediksi

5 langkah: Raw Text β†’ Token β†’ Integer β†’ Embedding β†’ Model β†’ Prediction

πŸ”„ NLP Pipeline β€” Dari Kalimat Mentah ke Prediksi

β‘  Raw Text "Film ini sangat bagus sekali!" β‘‘ Tokenize ["film", "ini", "sangat", "bagus", "sekali"] β‘’ Encode [42, 7, 156, 89, 234] kata β†’ integer ID β‘£ Embedding [0.2, -0.1, 0.8, 0.3, -0.5, ...] [0.1, 0.7, -0.3, 0.9, 0.2, ...] ID β†’ dense vector β‘€ Model LSTM / Transformer β†’ Positif 😊 confidence: 94.7% Tokenization Pecah kalimat jadi potongan kata. Hapus punctuation, lowercase. Tools: spaCy, NLTK, Hugging Face "sangat bagus!" β†’ ["sangat","bagus"] Vocabulary & Encoding Buat kamus: setiap kata unik β†’ ID angka. {"film": 42, "bagus": 89, ...} Padding: buat semua teks panjang sama. ["bagus","film"] β†’ [89, 42, 0, 0, 0] Embedding Layer Ubah integer ID β†’ dense vector (50-300 dim). Kata mirip β†’ vektor dekat di ruang embedding. "bagus" β‰ˆ "hebat" β‰ˆ "keren" (dekat) "bagus" β‰  "buruk" (jauh) Pipeline ini mengubah "Film ini sangat bagus sekali!" menjadi tensor yang bisa diproses neural network
βœ‚οΈ

3. Tokenization β€” Pecah Teks Jadi Token

Dari kalimat β†’ list kata β†’ list angka
16_tokenization.py β€” Dari Teks ke Angka
import re from collections import Counter # =========================== # 1. Tokenisasi sederhana # =========================== def tokenize(text): """Pecah teks jadi list kata (lowercase, no punctuation)""" text = text.lower() # lowercase text = re.sub(r'[^a-zA-Z\s]', '', text) # hapus punctuation return text.split() # pecah by spasi review = "This movie was absolutely amazing! Best film of 2026." tokens = tokenize(review) print(tokens) # ['this', 'movie', 'was', 'absolutely', 'amazing', # 'best', 'film', 'of', ''] # =========================== # 2. Bangun Vocabulary # =========================== # Kumpulkan semua kata dari seluruh dataset all_reviews = [ "This movie was great", "Terrible film, waste of time", "Amazing acting and story", "Boring and predictable", ] # Hitung frekuensi setiap kata word_counts = Counter() for review in all_reviews: word_counts.update(tokenize(review)) # Buat mapping: kata β†’ angka vocab = {'<PAD>': 0, '<UNK>': 1} # Token khusus for word, count in word_counts.most_common(5000): vocab[word] = len(vocab) print(f"Vocabulary size: {len(vocab)}") # Vocabulary size: 16 # =========================== # 3. Encode: kata β†’ angka # =========================== def encode(text, vocab, max_len=50): tokens = tokenize(text) ids = [vocab.get(t, vocab['<UNK>']) for t in tokens] # Padding: pastikan panjang sama ids = ids[:max_len] # truncate jika terlalu panjang ids += [0] * (max_len - len(ids)) # pad dengan 0 jika terlalu pendek return ids encoded = encode("This movie was great", vocab) print(encoded[:10]) # [5, 3, 6, 7, 0, 0, 0, 0, 0, 0] # ↑this ↑movie ↑was ↑great ↑...padding...

πŸŽ“ Special Tokens

<PAD> (ID 0): padding β€” mengisi tempat kosong agar semua input panjang sama. Neural network butuh input fixed-size.
<UNK> (ID 1): unknown β€” kata yang tidak ada di vocabulary. Muncul saat inference dengan kata baru yang belum pernah dilihat saat training.

🌐

4. Word Embeddings β€” Kata dalam Ruang Makna

Setiap kata = vektor. Kata mirip β†’ vektor dekat.

Integer ID (42, 89, 156) tidak mengandung informasi tentang makna kata. Angka 42 tidak lebih "mirip" dengan 43 daripada dengan 1000. Word Embedding menyelesaikan ini: setiap kata direpresentasikan sebagai vektor padat (50-300 dimensi) di mana kata-kata dengan makna mirip memiliki vektor yang dekat satu sama lain.

🌐 Word Embedding Space β€” Kata Mirip = Posisi Dekat

Dimensi 1 Dimensi 2 Cluster: Positif 😊 great amazing excellent wonderful Cluster: Negatif 😠 terrible awful boring movie film dekat! βœ“ jauh! βœ— Bagaimana Embedding Bekerja β‘  Setiap kata β†’ vektor 100 dimensi "great" β†’ [0.2, -0.1, 0.8, ...] β‘‘ nn.Embedding: lookup table yang bisa belajar nn.Embedding(vocab_size, 100) β‘’ Training: vektor otomatis menyesuaikan agar kata positif dekat satu sama lain dan jauh dari kata negatif β‘£ Bisa pakai pre-trained (GloVe, Word2Vec) β†’ Sudah belajar dari miliaran kata!
17_embedding.py β€” nn.Embedding
import torch import torch.nn as nn # Embedding layer: lookup table kata β†’ vektor vocab_size = 5000 # Ukuran vocabulary embed_dim = 100 # Dimensi embedding per kata embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0) # ↑ padding_idx=0 β†’ vektor untuk <PAD> selalu nol # Input: batch of token IDs input_ids = torch.tensor([[42, 7, 156, 89, 0], # review 1 [23, 45, 0, 0, 0]]) # review 2 (shorter, padded) # Output: setiap ID β†’ vektor 100-dimensi embedded = embedding(input_ids) print(embedded.shape) # torch.Size([2, 5, 100]) # ↑batch=2 ↑seq_len=5 ↑embed_dim=100 # Setiap kata sekarang punya "alamat" di ruang 100-dimensi!
πŸ”„

5. LSTM β€” Network yang "Ingat" Urutan

Long Short-Term Memory: membaca kata per kata, ingat konteks

LSTM (Long Short-Term Memory) membaca teks satu kata per langkah, sambil menyimpan "memori" tentang kata-kata sebelumnya. Ini memungkinkan LSTM memahami konteks: "not good" β†’ negatif (bukan positif meskipun ada "good").

πŸ”„ LSTM Unrolled β€” Membaca Kata per Kata dengan Memori

"this" "movie" "was" "amazing" "!" LSTM LSTM LSTM LSTM LSTM h₁ hβ‚‚ h₃ hβ‚„ FC β†’ Softmax Positif 😊 Hidden state terakhir = "ringkasan" seluruh kalimat hβ‚€ h = hidden state: "memori" yang diteruskan ke langkah berikutnya. Berisi ringkasan semua kata yang sudah dibaca.
πŸ’»

6. Kode: Sentiment Classifier (LSTM)

Positif atau Negatif β€” dari IMDb movie reviews
18_sentiment_lstm.py β€” Full Sentiment Classifier
import torch import torch.nn as nn class SentimentLSTM(nn.Module): def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes): super().__init__() # Layer 1: Embedding (kata β†’ vektor) self.embedding = nn.Embedding( vocab_size, embed_dim, padding_idx=0 ) # Layer 2: LSTM (proses urutan kata) self.lstm = nn.LSTM( input_size=embed_dim, # Ukuran embedding hidden_size=hidden_dim, # Ukuran hidden state num_layers=2, # 2 layer LSTM (stacked) batch_first=True, # Input shape: [batch, seq, feature] bidirectional=True, # Baca maju DAN mundur dropout=0.3 # Dropout antar layer LSTM ) # Layer 3: Classifier head self.dropout = nn.Dropout(0.5) self.fc = nn.Linear(hidden_dim * 2, num_classes) # ↑ Γ—2 karena bidirectional (forward + backward) def forward(self, x): # x shape: [batch, seq_len] (token IDs) embedded = self.embedding(x) # β†’ [batch, seq_len, embed_dim] lstm_out, (hidden, cell) = self.lstm(embedded) # hidden shape: [num_layers*2, batch, hidden_dim] # Ambil hidden state terakhir (forward + backward) hidden_fwd = hidden[-2] # Last forward layer hidden_bwd = hidden[-1] # Last backward layer hidden_cat = torch.cat([hidden_fwd, hidden_bwd], dim=1) # β†’ [batch, hidden_dim * 2] output = self.dropout(hidden_cat) output = self.fc(output) # β†’ [batch, num_classes] return output # Inisialisasi model model = SentimentLSTM( vocab_size=25000, # 25K kata paling sering embed_dim=100, # Embedding 100-dimensi hidden_dim=256, # LSTM hidden 256 num_classes=2 # Positif atau Negatif ) total = sum(p.numel() for p in model.parameters()) print(f"Parameters: {total:,}") # Parameters: 3,456,002 # Training (sama pattern seperti Part 2-4!) loss_fn = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Hasil setelah 5 epoch pada IMDb dataset: # Epoch 1 | Loss: 0.6234 | Acc: 72.4% # Epoch 3 | Loss: 0.3821 | Acc: 84.1% # Epoch 5 | Loss: 0.2456 | Acc: 87.3% # Prediksi: # "This movie was absolutely terrible" β†’ Negatif (96.2%) # "Best film I've seen this year!" β†’ Positif (93.8%)

πŸŽ“ Bidirectional LSTM

LSTM biasa membaca kiri β†’ kanan saja. Bidirectional LSTM membaca dua arah: maju DAN mundur. Ini penting karena makna kata bisa bergantung pada kata setelahnya. Contoh: "The food was not bad" β€” kata "bad" berubah makna karena "not" di sebelumnya. Tapi "food" juga penting dan ada sebelum "not". Bidirectional menangkap kedua konteks.

πŸ€–

7. Transformer & Hugging Face β€” Masa Depan NLP

Dari LSTM ke Attention: fondasi GPT, BERT, Claude, dan semua LLM modern

LSTM bagus, tapi lambat (sequential, satu kata per langkah) dan susah menangkap hubungan jarak jauh. Transformer (2017) menyelesaikan kedua masalah ini dengan Self-Attention: setiap kata bisa langsung "memperhatikan" semua kata lain secara paralel. Ini fondasi semua LLM modern: GPT, BERT, Claude, Gemini, LLaMA.

🐌 LSTM

Sequential: satu kata per langkah. Lambat untuk teks panjang. Sulit menangkap hubungan kata yang jauh. Akurasi: ~87% (IMDb). Training: lambat.

⚑ Transformer (BERT)

Parallel: semua kata diproses sekaligus. Cepat. Self-Attention menghubungkan semua kata. Akurasi: ~95% (IMDb). Training: cepat (GPU).

19_huggingface_bert.py β€” Sentiment dengan BERT (5 baris!)
# pip install transformers from transformers import pipeline # Load pre-trained sentiment classifier β€” SATU BARIS! classifier = pipeline("sentiment-analysis") # Prediksi langsung β€” tanpa training! result = classifier("This movie was absolutely fantastic!") print(result) # [{'label': 'POSITIVE', 'score': 0.9998}] result = classifier("Terrible acting, boring plot.") print(result) # [{'label': 'NEGATIVE', 'score': 0.9994}] # Batch prediction results = classifier([ "I loved every minute of this film", "Waste of time and money", "Decent movie, nothing special" ]) for r in results: print(f"{r['label']:8s} ({r['score']:.2%})") # POSITIVE (99.98%) # NEGATIVE (99.89%) # POSITIVE (74.32%)
🀯 5 Baris Kode! Hugging Face pipeline memberikan akses ke ribuan model pre-trained. Tidak perlu tokenization manual, training, atau apapun β€” langsung prediksi. Ini kekuatan ekosistem: seseorang sudah melatih model pada jutaan review, dan Anda tinggal pakai. Untuk fine-tune ke domain Anda sendiri, Hugging Face juga menyediakan Trainer API.
20_finetune_bert.py β€” Fine-tune BERT untuk Data Anda
from transformers import ( AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments ) # Load pre-trained BERT + tokenizer model_name = "bert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained( model_name, num_labels=2 # Positif / Negatif ) # Tokenize dataset Anda def tokenize_fn(examples): return tokenizer( examples["text"], padding="max_length", truncation=True, max_length=256 ) # Training arguments args = TrainingArguments( output_dir="./results", num_train_epochs=3, per_device_train_batch_size=16, learning_rate=2e-5, # LR kecil untuk fine-tune! evaluation_strategy="epoch", ) # Train! trainer = Trainer( model=model, args=args, train_dataset=train_dataset, # Dataset Anda eval_dataset=eval_dataset, ) trainer.train() # Hasil: 93-95% akurasi setelah fine-tune 3 epoch! # Jauh lebih baik dari LSTM (87%) dengan effort minimal.
⚠️ LSTM vs Transformer β€” Kapan Pakai Mana? Gunakan LSTM jika: resource terbatas (CPU), dataset kecil, atau perlu memahami arsitektur dari dasar. Gunakan Transformer/BERT jika: butuh akurasi terbaik, punya GPU, dan dataset cukup besar. Di 2026, Transformer adalah default choice untuk production NLP.
πŸ“

8. Ringkasan Part 5

Konsep NLP yang kita kuasai
KonsepApa ItuKode Kunci
TokenizationPecah teks β†’ list kata/sub-katatext.lower().split()
VocabularyMapping kata β†’ integer ID{"word": 42, ...}
PaddingBuat semua input panjang samaids += [0] * (max_len - len)
nn.EmbeddingLookup table: ID β†’ dense vectornn.Embedding(vocab, dim)
nn.LSTMSequential model yang ingat konteksnn.LSTM(input, hidden, layers)
BidirectionalBaca maju DAN mundurbidirectional=True
Hidden State"Memori" LSTM β€” ringkasan urutan_, (hidden, cell) = lstm(x)
TransformerSelf-Attention: semua kata paralelFondasi GPT, BERT, Claude
Hugging FaceHub 100K+ pre-trained modelspipeline("sentiment-analysis")
Fine-tune BERTAdaptasi BERT ke domain AndaTrainer(model, args, dataset)

πŸ”₯ Perjalanan Kita: Part 1 β†’ Part 5

Part 1: Tensor Autograd, First NN y = 2x + 1 Part 2: MNIST Dataset, DataLoader 97.8% accuracy Part 3: CNN Conv, Pool, Dropout 99.2% accuracy Part 4: Transfer ResNet, Fine-tune 96%+ (5 epoch!) Part 5: NLP πŸ“ LSTM, Embeddings Transformer, BERT Hugging Face πŸ€—
πŸ”₯
Tech Review Desk β€” Seri Belajar PyTorch
Tutorial hands-on. Sumber: pytorch.org, Hugging Face docs, bentrevett/pytorch-sentiment-analysis, Analytics Vidhya. PyTorch v2.7+ (2026).
πŸ“§ rominur@gmail.com  β€’  ✈️ t.me/Jekardah_AI β€” For collaboration & discussion