CNN & RNN

5 jam16 min baca
Tujuan

Paham arsitektur CNN (image) dan RNN (sequence) — sebelum masuk Transformer.

03 — CNN & RNN

Estimasi: 5 jam Tujuan: Paham arsitektur CNN (image) dan RNN (sequence) — sebelum masuk Transformer.


Kenapa Materi Ini Penting?

Sebelum era Transformer (2017), dua arsitektur ini adalah "raja" deep learning: CNN untuk gambar, RNN untuk teks dan time series. Walaupun sekarang Transformer mendominasi, pengetahuan CNN dan RNN tetap esensial — banyak production system masih pakai mereka karena lebih ringan, dan banyak konsep modern (attention, residual connection, embedding) lahir dari pemahaman keterbatasan dua arsitektur ini.

Bayangkan dua "indera" yang berbeda: CNN melihat ruang (pixel berdekatan saling berhubungan), RNN merasakan waktu (kata sekarang tergantung kata sebelumnya). Memahami inductive bias mereka membantu kamu paham kenapa Transformer kemudian menggabungkan keduanya — Transformer sejatinya adalah RNN tanpa rekurensi yang juga bisa pakai positional encoding (kesadaran ruang/urutan).

Tiga insight kunci yang akan kamu kuasai: (1) Convolution sebagai cap berpola yang menggeser di gambar untuk capture local pattern, (2) Recurrence sebagai cara membaca sequence dengan "memori" hidden state, dan (3) Limitations mereka yang memunculkan ide self-attention.

Peta Mental: CNN vs RNN

flowchart LR
    subgraph CNN["🖼️ CNN — Spasial"]
        I1["Input image"] --> C1["Conv (cap pola)"]
        C1 --> P1["Pool (ringkas)"]
        P1 --> F1["Flatten + FC"]
    end
    subgraph RNN["📜 RNN — Temporal"]
        I2["Token t-1"] --> H1["Hidden state"]
        I3["Token t"] --> H1
        H1 --> H2["Hidden state'"]
        I4["Token t+1"] --> H2
    end
    style CNN fill:#dbeafe
    style RNN fill:#fef3c7

Bagian 1 — CNN (Convolutional Neural Network)

Kenapa Conv untuk Image?

Image punya spatial structure — pixel berdekatan berhubungan. Linear layer tidak tangkap ini.

Conv = filter sliding di image, capture local pattern.

Konsep Filter

Analogi Convolution: Bayangkan kamu punya stempel/cap kecil dengan pola tertentu (misal pola "tepi vertikal"). Kamu tempelkan cap itu ke seluruh permukaan gambar, geser sedikit demi sedikit, dan tiap posisi catat seberapa cocok pola cap dengan area gambar di bawahnya. Hasilnya adalah feature map — peta yang menunjukkan "di mana saja pola cap ini muncul di gambar". CNN punya banyak cap berbeda (filter berbeda), tiap cap belajar sendiri pola apa yang dia tangkap.

Image: 6×6                Filter: 3×3            Output: 4×4
[1 2 3 4 5 6]            [1 0 -1]              [...]
[7 8 9 0 1 2]            [1 0 -1]              [...]
[3 4 5 6 7 8]            [1 0 -1]              [...]
...                      (vertical edge)

Filter geser di image, hasilkan feature map.

Visualisasi Operasi Convolution

Cara Membaca Diagram:

  • Kiri = input image, tengah = bank filter, kanan = stacked output
  • Tiap filter belajar pola spesifik (tepi, sudut, tekstur, warna)
  • Hasil semua filter di-stack jadi tensor multi-channel
  • Bobot filter di-share di seluruh image (translation equivariance)

Walkthrough Step-by-Step:

  1. Input image masuk dengan shape (C_in, H, W), contoh (3, 32, 32)
  2. Filter 1, 2, ..., N — tiap satu cap kecil dengan pola tertentu
  3. Tiap filter di-slide ke seluruh image, hasilnya feature map 2-D
  4. Stack semua feature map jadi tensor (N, H', W') — banyak filter = banyak channel
  5. Output siap di-pool dan dimasukkan ke conv layer berikutnya

Analogi Sehari-hari: Convolution = ratusan stempel berbeda yang ditempelkan ke seluruh gambar. Tiap stempel mencatat "seberapa cocok pola saya dengan area ini". Hasilnya: peta berlapis yang menunjukkan di mana setiap pola muncul.

Diagram statis Mermaid sebagai fallback:

flowchart LR
    Img["🖼️ Input<br/>32×32×3"] --> K1["🔍 Filter 1<br/>(deteksi tepi)"]
    Img --> K2["🔍 Filter 2<br/>(deteksi sudut)"]
    Img --> K3["🔍 Filter N<br/>(deteksi tekstur)"]
    K1 --> FM1["📊 Feature Map 1"]
    K2 --> FM2["📊 Feature Map 2"]
    K3 --> FM3["📊 Feature Map N"]
    FM1 --> Stack["📦 Stack:<br/>30×30×N"]
    FM2 --> Stack
    FM3 --> Stack
    style Img fill:#dbeafe
    style Stack fill:#d1fae5

Pooling — Meringkas Tetangga

Analogi Pooling: Bayangkan kamu punya foto resolusi tinggi tapi mau kirim via WhatsApp — kamu kompres. MaxPool = "ambil pixel paling terang dari tiap 2×2 area". AvgPool = "rata-ratakan tiap 2×2 area". Hasilnya: gambar lebih kecil tapi fitur penting tetap terjaga. Di CNN, pooling membuat network: (1) lebih ringan, (2) invariant terhadap pergeseran kecil — kucing yang bergeser 2 pixel tetap terdeteksi sebagai kucing.

Cara Membaca Diagram:

  • Kiri = input grid, tengah = jenis pooling, kanan = output yang lebih kecil
  • MaxPool dan AvgPool dua opsi paling umum
  • Stride 2 = output 1/2 ukuran input di tiap dimensi spasial
  • Tidak ada parameter yang dipelajari (pure operasi)

Walkthrough Step-by-Step:

  1. Input — feature map 4×4 dari conv sebelumnya
  2. MaxPool 2×2 — bagi jadi 4 area 2×2, ambil nilai paling besar dari tiap area
  3. AvgPool 2×2 — bagi jadi 4 area 2×2, hitung rata-rata tiap area
  4. Hasilnya 2×2, ukuran setengah dari input
  5. Manfaat: ringan, invariant terhadap pergeseran kecil

Analogi Sehari-hari: Pooling = kompres foto WhatsApp. MaxPool = ambil pixel paling terang per area (highlight). AvgPool = blur ringan. Ukuran turun, tapi info penting tetap kebaca.

Diagram statis Mermaid sebagai fallback:

flowchart LR
    Input["🟦 4×4<br/>1 2 3 4<br/>5 6 7 8<br/>9 0 1 2<br/>3 4 5 6"] -->|"MaxPool 2×2"| Output["🟦 2×2<br/>6 8<br/>9 6"]
    style Input fill:#fef3c7
    style Output fill:#d1fae5

Full CNN Architecture (Big Picture)

Cara Membaca Diagram:

  • Atas = pipeline conv+pool yang menyusutkan ukuran spasial
  • Bawah = head FC untuk klasifikasi
  • Tiap conv block: Conv → ReLU → MaxPool, diulang 3 kali
  • Spatial size turun 32 → 16 → 8 → 4, depth naik 3 → 32 → 64 → 128

Walkthrough Step-by-Step:

  1. Input image 3×32×32 (RGB CIFAR-style)
  2. Conv1 dengan 32 filter → output 32×32×32
  3. MaxPool → 32×16×16 (spatial half)
  4. Conv2 + Pool → 64×8×8
  5. Conv3 + Pool → 128×4×4
  6. Flatten ke vector 2048
  7. FC + Softmax → probability tiap class
  8. Output prediksi class

Analogi Sehari-hari: CNN = pyramid info. Layer awal nangkap detail kecil (garis, warna). Layer tengah gabungkan jadi pola (mata, telinga). Layer akhir gabungkan pola jadi konsep (kucing, anjing). FC head jadi "juri" yang vote.

Diagram statis Mermaid sebagai fallback:

flowchart LR
    I["🖼️ Image<br/>3×32×32"] --> C1["Conv1<br/>32 filter"]
    C1 --> A1["ReLU"]
    A1 --> P1["MaxPool<br/>16×16"]
    P1 --> C2["Conv2<br/>64 filter"]
    C2 --> A2["ReLU"]
    A2 --> P2["MaxPool<br/>8×8"]
    P2 --> C3["Conv3<br/>128 filter"]
    C3 --> A3["ReLU"]
    A3 --> P3["MaxPool<br/>4×4"]
    P3 --> F["Flatten"]
    F --> FC["FC + Softmax"]
    FC --> Out["🎯 Class"]
    style I fill:#dbeafe
    style Out fill:#d1fae5

CNN Architecture

import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)    # input 3 channel (RGB)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        self.pool = nn.MaxPool2d(2, 2)
        
        self.fc1 = nn.Linear(128 * 4 * 4, 256)    # untuk image 32×32
        self.fc2 = nn.Linear(256, num_classes)
        
        self.dropout = nn.Dropout(0.5)
    
    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))   # 32×32 → 16×16
        x = self.pool(torch.relu(self.conv2(x)))   # 16×16 → 8×8
        x = self.pool(torch.relu(self.conv3(x)))   # 8×8 → 4×4
        
        x = x.view(x.size(0), -1)                   # flatten
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x

Common Components

  • Conv layer — extract local features
  • Pooling — downsample, reduce dimension
  • Activation — ReLU klasik
  • BatchNorm — stabilize training

Famous Architectures (Sekedar Tahu)

  • AlexNet (2012) — winner ImageNet, mulai era deep learning
  • VGG (2014) — deeper, simple
  • ResNet (2015) — skip connection, allow very deep
  • Inception (GoogLeNet)
  • EfficientNet — modern, efficient

Transfer Learning (Pakai Pretrained)

import torchvision.models as models

# Pretrained on ImageNet
model = models.resnet50(weights="DEFAULT")

# Freeze backbone
for param in model.parameters():
    param.requires_grad = False

# Replace head
model.fc = nn.Linear(2048, num_classes_yours)

# Train head saja
optimizer = optim.Adam(model.fc.parameters(), lr=1e-3)

Wajib pakai transfer learning untuk image task. Train dari nol = boros, jelek.


CNN dengan nn.Sequential (Lebih Singkat)

cnn = nn.Sequential(
    nn.Conv2d(3, 32, 3, padding=1),
    nn.BatchNorm2d(32),
    nn.ReLU(),
    nn.MaxPool2d(2),                    # 32→16

    nn.Conv2d(32, 64, 3, padding=1),
    nn.BatchNorm2d(64),
    nn.ReLU(),
    nn.MaxPool2d(2),                    # 16→8

    nn.Conv2d(64, 128, 3, padding=1),
    nn.BatchNorm2d(128),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d((1, 1)),       # global pool → (B, 128, 1, 1)

    nn.Flatten(),
    nn.Dropout(0.5),
    nn.Linear(128, 10),
)

Tip: AdaptiveAvgPool2d((1,1)) membuat network tidak peduli ukuran input — bisa terima image 32×32 atau 224×224 dengan FC head yang sama. Pattern ini dipakai di ResNet & EfficientNet.


Bagian 2 — RNN (Recurrent Neural Network)

Kenapa RNN untuk Sequence?

Text, audio, time series punya temporal structure. Output kata ke-N tergantung kata ke-1...N-1.

Konsep Vanilla RNN

Analogi RNN: Bayangkan kamu membaca buku sambil ngomong sendiri — tiap kata baru, kamu bisikkan ringkasan apa yang kamu mengerti sejauh ini. "Hidden state" itu = bisikan ringkasan kamu. Tiap kali baca kata baru, bisikan di-update berdasarkan kata baru + bisikan sebelumnya. Begitu sampai akhir kalimat, bisikan terakhir = pemahaman keseluruhan kalimat. Itulah RNN — pembaca yang ingat kata-kata sebelumnya.

h_t = tanh(W_h × h_{t-1} + W_x × x_t + b)

Hidden state h membawa "memori" dari past.

Visualisasi RNN Unrolled

Cara Membaca Diagram:

  • Kiri ke kanan = waktu (timestep), tiap kolom = satu langkah
  • Atas = input token, tengah = RNN cell, bawah = hidden state mengalir
  • Bobot W_h, W_x sama di semua RNN cell — itu yang bikin "recurrent"
  • Hidden state membawa "memori" dari kata-kata sebelumnya

Walkthrough Step-by-Step:

  1. Mulai dengan h₀ (biasanya zeros)
  2. t=1: input x₁='Saya' + h₀ → cell hitung h₁
  3. t=2: input x₂='suka' + h₁ → cell hitung h₂
  4. t=3: input x₃='belajar' + h₂ → cell hitung h₃
  5. h₃ = ringkasan seluruh sequence, siap dipakai untuk klasifikasi/generation

Analogi Sehari-hari: RNN = kamu baca novel sambil ngomong sendiri. Tiap kalimat baru, kamu update bisikan ringkasan di kepala. Bisikan sebelumnya + kalimat baru → bisikan baru. Begitu terus sampai akhir bab.

Diagram statis Mermaid sebagai fallback:

flowchart LR
    H0["🧠 h₀<br/>(awal kosong)"] --> R1["⚙️ RNN cell"]
    X1["📝 x₁<br/>'Saya'"] --> R1
    R1 --> H1["🧠 h₁"]
    H1 --> R2["⚙️ RNN cell"]
    X2["📝 x₂<br/>'suka'"] --> R2
    R2 --> H2["🧠 h₂"]
    H2 --> R3["⚙️ RNN cell"]
    X3["📝 x₃<br/>'belajar'"] --> R3
    R3 --> H3["🧠 h₃<br/>(final)"]
    style H0 fill:#fef3c7
    style H3 fill:#d1fae5
    style R1 fill:#dbeafe
    style R2 fill:#dbeafe
    style R3 fill:#dbeafe

Yang membuat RNN "recurrent": bobot yang sama (W_h, W_x) dipakai di tiap timestep. Ini efisien — bisa proses sequence panjang tanpa nambah parameter.

import torch.nn as nn

rnn = nn.RNN(input_size=10, hidden_size=20, num_layers=2, batch_first=True)

x = torch.randn(32, 50, 10)    # (batch, seq, dim)
output, hidden = rnn(x)
# output: (32, 50, 20)  — output per timestep
# hidden: (2, 32, 20)   — final hidden state

Masalah Vanilla RNN

  • Vanishing gradient — sulit belajar long-range dependency
  • Exploding gradient — gradient meledak saat backprop

Solusi: LSTM dan GRU.


Bagian 3 — LSTM (Long Short-Term Memory)

LSTM punya gate mechanism untuk handle long-range dependency.

Analogi LSTM: Kalau RNN biasa = pembaca yang cuma bisikan ringkasan singkat (gampang lupa kata di awal kalimat panjang), LSTM = pembaca dengan buku catatan. Di tiap timestep, dia punya 3 keputusan: (1) Forget gate — apa yang dihapus dari catatan ("ah, ini tidak penting"), (2) Input gate — apa yang ditambahkan ke catatan ("ini perlu kuingat"), (3) Output gate — apa yang diomongkan keluar ("yang ini cocok jadi output"). Cell state c = isi buku catatan yang awet melintasi waktu, beda dari hidden state h yang lebih "sementara".

Visualisasi LSTM Cell

Cara Membaca Diagram:

  • Kiri = input ke cell (h_{t-1}, x_t), kanan = output (h_t, c_t)
  • Tiga gate kuning di tengah = forget, input, output (semua learnable)
  • c (cell state) = "buku catatan" awet, jalur lurus dari kiri ke kanan
  • h (hidden state) = output yang lebih sementara, dipakai layer/timestep berikut

Walkthrough Step-by-Step:

  1. Concat h_{t-1} dan x_t jadi satu vektor input
  2. Forget gate (sigmoid) — putuskan info di c_{t-1} mana yang dibuang
  3. Input gate — putuskan info baru apa yang ditambahkan ke cell state
  4. Update cell state: c_t = forget × c_{t-1} + input_value
  5. Output gate — putuskan apa yang dilihat keluar sebagai h_t
  6. h_t = tanh(c_t) × output_gate

Analogi Sehari-hari: LSTM = ngerjain skripsi sambil bawa notebook. Forget gate = coret bagian tak relevan. Input gate = tulis insight baru. Output gate = pilih apa yang ditampilkan ke pembimbing. Cell state (c) = isi notebook yang lengkap, hidden state (h) = ringkasan yang ditunjukkan.

Diagram statis Mermaid sebagai fallback:

flowchart LR
    HPrev["🧠 h_{t-1}"] --> Concat["⚙️ Concat"]
    XT["📝 x_t"] --> Concat
    Concat --> Forget["🗑️ Forget Gate<br/>(σ)"]
    Concat --> Input["➕ Input Gate<br/>(σ × tanh)"]
    Concat --> Output["📤 Output Gate<br/>(σ)"]
    CPrev["📔 c_{t-1}<br/>memory"] --> Mul1["× forget"]
    Forget --> Mul1
    Mul1 --> Add["+"]
    Input --> Add
    Add --> CNew["📔 c_t<br/>new memory"]
    CNew --> Tanh["tanh"]
    Tanh --> Mul2["× output"]
    Output --> Mul2
    Mul2 --> HNew["🧠 h_t"]
    style CPrev fill:#fef3c7
    style CNew fill:#d1fae5
    style HNew fill:#dbeafe
lstm = nn.LSTM(input_size=10, hidden_size=20, num_layers=2, batch_first=True)

x = torch.randn(32, 50, 10)
output, (h, c) = lstm(x)
# output: (32, 50, 20)
# h: (2, 32, 20)  — hidden
# c: (2, 32, 20)  — cell state

LSTM Gates

  • Forget gate — apa yang dilupa
  • Input gate — apa yang ditambah ke memori
  • Output gate — apa yang di-output

Detail teknis: tidak perlu hafal, paham konsep "gating".


Bagian 4 — GRU (Lebih Sederhana, Sering Cukup)

gru = nn.GRU(input_size=10, hidden_size=20, num_layers=2, batch_first=True)

output, hidden = gru(x)

GRU = simplified LSTM, lebih cepat, sering performance mirip.


Bagian 5 — Bidirectional

lstm = nn.LSTM(input_size=10, hidden_size=20, bidirectional=True, batch_first=True)
# Output dim = 2 × hidden_size = 40

Process dari kiri dan kanan. Bagus untuk task yang butuh konteks dua arah (NER, sentiment analysis).


Bagian 6 — Sequence-to-Sequence (Encoder-Decoder)

Pattern untuk translation, summarization (sebelum era transformer).

Input: "I love AI"
   ↓
[Encoder RNN]
   ↓
Context vector
   ↓
[Decoder RNN]
   ↓
Output: "Saya cinta AI"

Attention (Sebelum Transformer)

Vanilla seq2seq punya bottleneck di context vector. Attention allows decoder "lihat" semua encoder output, weighted.

Ini cikal bakal Transformer. Self-attention = attention tanpa encoder/decoder split.


Bagian 7 — Kapan Pakai Apa?

Sebelum era Transformer (~2018):

  • Image → CNN
  • Sequence → RNN/LSTM
  • Translation → Seq2Seq + attention

Sekarang (2026):

  • Image → CNN masih dominan untuk many task, tapi ViT (Vision Transformer) menang di scale besar
  • Sequence/text → Transformer (file 05) hampir selalu menang

RNN/LSTM masih dipakai di:

  • Edge devices (low-resource)
  • Time series sederhana
  • Audio processing dengan WaveNet

Tapi untuk NLP modern, langsung lompat ke Transformer.


Bagian 7 — Kapan Pakai Apa?

Sebelum era Transformer (~2018):

  • Image → CNN
  • Sequence → RNN/LSTM
  • Translation → Seq2Seq + attention

Sekarang (2026):

  • Image → CNN masih dominan untuk many task, tapi ViT (Vision Transformer) menang di scale besar
  • Sequence/text → Transformer (file 05) hampir selalu menang

RNN/LSTM masih dipakai di:

  • Edge devices (low-resource)
  • Time series sederhana
  • Audio processing dengan WaveNet

Tapi untuk NLP modern, langsung lompat ke Transformer.

Comparison Table: CNN vs RNN vs Transformer

Aspek CNN RNN/LSTM Transformer
Inductive bias Local pattern (translation invariance) Sequential, recency Global, position-agnostic
Parallelize ✅ Tinggi (per pixel) ❌ Rendah (sequential) ✅✅ Sangat tinggi
Long-range dependency Terbatas (receptive field) Sulit (vanishing gradient) ✅ Native (self-attention)
Compute per token O(k²) (kernel kecil) O(d²) O(n²·d) — quadratic di seq
Best for Image, audio spectrogram Time series kecil, edge Text, image (ViT), apa saja di scale besar
Modern share Image task tertentu Niche LLM, modern NLP, ViT

LSTM vs GRU

Aspek LSTM GRU
Gates 3 (forget, input, output) 2 (update, reset)
State hidden + cell hidden saja
Parameter Lebih banyak Lebih sedikit (~25% lebih kecil)
Speed Lebih lambat Lebih cepat
Performance Sedikit lebih baik di task panjang Sering setara, cocok data terbatas
Default pick Default klasik Pilihan modern saat data sedikit

Bagian 8 — Common Mistakes & FAQ

CNN Side

1. Tidak Pakai Transfer Learning untuk Image

# ❌ Train ResNet-50 dari nol di dataset 5000 gambar = waste of GPU
model = models.resnet50(weights=None)

# ✅ Mulai dari ImageNet weights
model = models.resnet50(weights="DEFAULT")
model.fc = nn.Linear(2048, num_classes)

2. Lupa Normalize Input

# ❌ Image 0-255 langsung masuk model = aktivasi meledak
img_tensor = transforms.ToTensor()(img)        # 0-1 OK, tapi belum normalize

# ✅ Pakai ImageNet stats (kalau pakai pretrained)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                          std=[0.229, 0.224, 0.225]),
])

3. Conv2d In/Out Channel Salah

# ❌ RGB image (3 channel) tapi conv1 expect 1 channel
self.conv1 = nn.Conv2d(1, 32, 3)        # untuk grayscale

# ✅
self.conv1 = nn.Conv2d(3, 32, 3)        # untuk RGB

RNN Side

4. Tidak Pakai batch_first=True

# Default PyTorch: (seq, batch, feature) — bingung
rnn = nn.LSTM(10, 20)
x = torch.randn(50, 32, 10)             # (T, B, F)

# ✅ Lebih intuitif
rnn = nn.LSTM(10, 20, batch_first=True)
x = torch.randn(32, 50, 10)             # (B, T, F)

5. Variable Length Sequences Tanpa Padding

# ❌ Sequence panjang berbeda → error stack di DataLoader
batch = [torch.randn(10), torch.randn(15), torch.randn(8)]    # mixed length

# ✅ Pakai pad_sequence + pack_padded_sequence
from torch.nn.utils.rnn import pad_sequence, pack_padded_sequence

padded = pad_sequence(batch, batch_first=True)         # pad ke 15
lengths = torch.tensor([10, 15, 8])
packed = pack_padded_sequence(padded, lengths, batch_first=True, enforce_sorted=False)
output, (h, c) = lstm(packed)

6. Exploding Gradient — Wajib Clip

# ✅ Gradient clipping untuk RNN/LSTM
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()

Bug klasik: training RNN mendadak loss = NaN setelah beberapa epoch. Hampir selalu = exploding gradient. Clip dulu, baru langkah.


Cek Pemahaman

  • Tahu kenapa CNN bagus untuk image?
  • Bisa bikin simple CNN untuk klasifikasi?
  • Tahu kenapa RNN untuk sequence?
  • Tahu beda LSTM dan GRU?
  • Tahu kenapa Transformer mengalahkan RNN?

Challenge 6.3

Challenge 1 — CIFAR-10 CNN

from torchvision.datasets import CIFAR10

Build CNN untuk klasifikasi 10 class. Target accuracy >70%.

Challenge 2 — Transfer Learning

Pakai ResNet50 pretrained. Fine-tune untuk dataset gambar custom (atau Cats vs Dogs). Bandingkan dengan train from scratch.

Challenge 3 — RNN Sentiment Analysis

Dataset IMDB (review film). Build LSTM untuk klasifikasi sentiment. Pakai embedding layer.

Challenge 4 — Karpathy Episode 2

Tonton "Building makemore" Episode 1 (bigram model). Memahami language modeling fundamental.


Selanjutnya: 04-nlp-fundamentals.md