Machine Learning Academy · Pelajaran

RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan

Pelajar akan melaksanakan sel RNN satu langkah secara manual, mengembangkannya merentasi jujukan pendek, dan memvisualisasikan cara keadaan tersembunyi mengumpulkan konteks.

Pelajaran 1 daripada 413 langkah

RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan ialah pelajaran Machine Learning Academy percuma di CoddyKit. Ini ialah pelajaran 1 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Machine Learning Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Machine Learning Academy merangkumi sejumlah 4 pelajaran.

Mengapa Kita Memerlukan Rangkaian Berulang

Rangkaian suapan hadapan standard mengendalikan setiap input secara berasingan — rangkaian ini tidak mempunyai ingatan terhadap input sebelumnya. Namun, banyak masalah dunia sebenar melibatkan data berjujukan yang konteks masa lalu penting: meramalkan perkataan seterusnya dalam ayat, meramalkan harga saham esok berdasarkan data sejarah, atau mengelaskan gerak isyarat daripada jujukan bingkai video. Rangkaian Neural Berulang (RNN) menyelesaikan masalah ini dengan mengekalkan keadaan tersembunyi yang membawa maklumat merentasi langkah masa.

# Examples of sequential data:
sequences = {
    'NLP': 'The cat sat on the ___  (predict next word)',
    'Time Series': '[1.2, 1.5, 1.3, 1.8, ???]',
    'Speech': '[audio_t0, audio_t1, ..., audio_tN]',
    'Video': '[frame_1, frame_2, ..., frame_T]',
    'DNA': 'ATCGATCG... (biological sequence)',
}
for name, example in sequences.items():
    print(f'{name}: {example}')

Sel RNN Asas

Sel RNN asas menerima dua input: input semasa x_t dan keadaan tersembunyi sebelumnya h_{t-1}. Sel ini menghasilkan keadaan tersembunyi seterusnya h_t menggunakan formula: h_t = tanh(W_hh * h_{t-1} + W_xh * x_t + b). Matriks pemberat W_hh dan W_xh yang sama digunakan pada setiap langkah masa — ini ialah perkongsian pemberat merentasi masa, serupa dengan cara CNN berkongsi pemberat merentasi ruang. Keadaan tersembunyi membawa ingatan rangkaian tentang semua input terdahulu.

import torch

def rnn_cell(x_t, h_prev, W_xh, W_hh, b):
    '''One step of a vanilla RNN cell'''
    # x_t: (batch, input_size)
    # h_prev: (batch, hidden_size)
    h_t = torch.tanh(
        x_t @ W_xh.T +    # input contribution
        h_prev @ W_hh.T +  # hidden-to-hidden contribution
        b                  # bias
    )
    return h_t

# Example: input_size=4, hidden_size=8
batch = 3
x_t   = torch.randn(batch, 4)
h_prev = torch.zeros(batch, 8)
W_xh  = torch.randn(8, 4) * 0.01
W_hh  = torch.randn(8, 8) * 0.01
b     = torch.zeros(8)
h_t = rnn_cell(x_t, h_prev, W_xh, W_hh, b)
print(h_t.shape)   # (3, 8)

Membuka Lipatan RNN Merentasi Masa

Untuk memproses jujukan sepanjang T, sel RNN digunakan sebanyak T kali dalam satu gelung — proses ini dipanggil membuka lipatan melalui masa. Keadaan tersembunyi daripada langkah t-1 dihantar ke langkah t, lalu menghubungkan semua langkah masa. Semasa perambatan balik, kecerunan perlu mengalir kembali merentasi setiap langkah masa — proses ini dipanggil Backpropagation Through Time (BPTT). Kedalaman graf yang telah dibuka lipatannya sama dengan panjang jujukan, lalu menimbulkan cabaran bagi jujukan panjang.

import torch
import torch.nn as nn

# Unroll RNN manually over a sequence
batch_size, seq_len, input_size, hidden_size = 4, 10, 8, 16

rnn_cell = nn.RNNCell(input_size, hidden_size)
sequence = torch.randn(seq_len, batch_size, input_size)

h = torch.zeros(batch_size, hidden_size)  # initial hidden state
hidden_states = []

for t in range(seq_len):
    x_t = sequence[t]   # (batch, input_size)
    h = rnn_cell(x_t, h)  # apply RNN cell
    hidden_states.append(h)

print('Final hidden state:', h.shape)     # (4, 16)
print('All hidden states:', len(hidden_states), 'steps')

Menggunakan nn.RNN: Versi Modul

nn.RNN mengendalikan proses membuka lipatan secara automatik. Ia menerima input berbentuk (seq_len, batch, input_size) (atau (batch, seq_len, input_size) dengan batch_first=True) dan mengembalikan semua keadaan tersembunyi serta keadaan tersembunyi akhir. Parameter utama: num_layers menyusun berbilang lapisan RNN; bidirectional=True memproses jujukan dalam kedua-dua arah; dropout menggunakan dropout antara lapisan dalam RNN berbilang lapisan.

import torch
import torch.nn as nn

rnn = nn.RNN(
    input_size=16,
    hidden_size=32,
    num_layers=2,
    batch_first=True,    # input: (batch, seq, features)
    dropout=0.2          # between layers
)

X = torch.randn(8, 20, 16)   # batch=8, seq=20, features=16
output, h_n = rnn(X)

print('Output shape:', output.shape)   # (8, 20, 32) all steps
print('h_n shape:', h_n.shape)         # (2, 8, 32) last hidden

Pemulaan Keadaan Tersembunyi

Keadaan tersembunyi awal h_0 dihantar sebagai argumen kedua kepada nn.RNN. Jika tidak diberikan, nilai lalainya ialah sifar. Untuk pengelasan jujukan, keadaan tersembunyi akhir h_n merumuskan keseluruhan jujukan. Untuk tugas jujukan-ke-jujukan, semua keadaan tersembunyi perantaraan dalam output digunakan. Memulakan h_0 dengan sifar ialah amalan standard; sesetengah aplikasi mempelajari keadaan awal sebagai parameter untuk meningkatkan prestasi pada jujukan pendek.

import torch
import torch.nn as nn

rnn = nn.RNN(8, 16, batch_first=True)
X = torch.randn(4, 10, 8)   # batch=4, seq=10, input=8

# Default: h_0 = zeros
output, h_n = rnn(X)
print('h_n with zero init:', h_n.shape)  # (1, 4, 16)

# Custom initial hidden state
h_0 = torch.randn(1, 4, 16)  # (num_layers, batch, hidden)
output, h_n = rnn(X, h_0)
print('h_n with custom init:', h_n.shape)  # (1, 4, 16)

Pengelasan Jujukan dengan Keadaan Tersembunyi Akhir

Aplikasi RNN yang lazim ialah pengelasan jujukan: diberikan satu jujukan, ramalkan satu label kelas. Pendekatan standard ialah menggunakan hanya keadaan tersembunyi akhir h_n sebagai input kepada pengelas linear, kerana keadaan itu telah melihat seluruh jujukan setakat ini. Bagi RNN dwiarah, gabungkan keadaan tersembunyi akhir arah hadapan dan arah belakang untuk menangkap konteks masa lalu serta masa hadapan.

import torch
import torch.nn as nn

class SequenceClassifier(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super().__init__()
        self.rnn = nn.RNN(input_size, hidden_size,
                          batch_first=True)
        self.fc  = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        _, h_n = self.rnn(x)
        # h_n shape: (1, batch, hidden) -> squeeze to (batch, hidden)
        h_n = h_n.squeeze(0)
        return self.fc(h_n)

model = SequenceClassifier(16, 32, 5)
X = torch.randn(8, 20, 16)
logits = model(X)
print(logits.shape)   # (8, 5) -- 8 samples, 5 classes

Banyak-ke-Banyak: Pelabelan Jujukan

Dalam tugasan pelabelan jujukan (penandaan POS, pengecaman entiti bernama, pengesanan anomali siri masa), anda memerlukan ramalan pada setiap timestep, bukan hanya pada timestep terakhir. Gunakan tensor output penuh daripada nn.RNN (bentuk: batch x seq_len x hidden_size) dan gunakan lapisan linear pada setiap timestep secara berasingan. Pemberat lapisan linear dikongsi merentas timestep — satu lagi contoh perkongsian pemberat dalam model jujukan.

import torch
import torch.nn as nn

class SequenceLabeler(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super().__init__()
        self.rnn = nn.RNN(input_size, hidden_size,
                          batch_first=True)
        self.fc  = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        output, _ = self.rnn(x)  # (batch, seq, hidden)
        return self.fc(output)   # (batch, seq, num_classes)

model = SequenceLabeler(8, 16, 3)
X = torch.randn(4, 10, 8)       # 4 seqs of 10 timesteps
logits = model(X)
print(logits.shape)              # (4, 10, 3) per-step labels

RNN Bertindan dan Dwiarah

RNN bertindan (num_layers > 1) menyalurkan output daripada satu lapisan RNN sebagai input kepada lapisan seterusnya, lalu mempelajari perwakilan temporal yang semakin abstrak. RNN dwiarah memproses jujukan secara serentak dalam arah hadapan (kiri ke kanan) dan arah belakang (kanan ke kiri), kemudian menggabungkan keadaan tersembunyi. Pemprosesan dwiarah membolehkan setiap output mengandungi konteks daripada masa lalu dan masa hadapan — berguna untuk memahami ayat apabila perkataan pada masa hadapan membantu menjelaskan maksud perkataan sebelumnya.

import torch
import torch.nn as nn

# Stacked bidirectional RNN
brnn = nn.RNN(
    input_size=16,
    hidden_size=32,
    num_layers=3,          # 3 stacked layers
    batch_first=True,
    bidirectional=True     # forward + backward
)

X = torch.randn(4, 10, 16)
output, h_n = brnn(X)

# Output: (batch, seq, hidden*2) because bidirectional
print('Output shape:', output.shape)  # (4, 10, 64)
# h_n: (num_layers*2, batch, hidden) -- 2 dirs x 3 layers
print('h_n shape:', h_n.shape)        # (6, 4, 32)

Rambatan Balik Merentasi Masa (BPTT)

Rambatan Balik Merentasi Masa membuka lipatan RNN dan menggunakan rambatan balik piawai pada graf yang telah dibuka lipatannya. Bagi jujukan sepanjang T, kecerunan dikira pada setiap timestep dan disebarkan ke belakang. Kecerunan terhadap parameter melibatkan hasil darab matriks pemberat W_hh yang sama sebanyak T kali. Apabila jejari spektrum W_hh kurang daripada 1, hasil darab ini lenyap; apabila lebih daripada 1, hasil darab ini meletup — inilah cabaran asas dalam melatih RNN pada jujukan yang panjang.

import torch
import torch.nn as nn

# Demonstrate gradient flow through different sequence lengths
rnn = nn.RNNCell(4, 8)
h = torch.zeros(1, 8, requires_grad=True)

# Short sequence: gradients flow back relatively well
for t in range(5):
    x = torch.randn(1, 4)
    h = rnn(x, h)
loss = h.sum()
loss.backward()
print('h.grad (seq=5):', h.grad.norm().item())

# For long sequences (T=100+), vanilla RNN gradients
# typically vanish (near zero) or explode (very large)
# This is why LSTM/GRU were invented

Mengendalikan Jujukan dengan Panjang Berubah-ubah

Dalam amalan, jujukan dalam satu kelompok mempunyai panjang yang berbeza (ayat dengan bilangan perkataan yang berbeza). PyTorch mengendalikan perkara ini dengan jujukan berpakej: torch.nn.utils.rnn.pack_padded_sequence membuang padding daripada kelompok dan memakejkan jujukan dengan cekap. Selepas RNN, pad_packed_sequence memulihkan format berpadded. Tanpa pemakejan, RNN memproses token padding tanpa keperluan dan mungkin mencemarkan keadaan tersembunyi dengan maklumat padding yang tidak bermakna.

import torch
import torch.nn as nn
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence

rnn = nn.RNN(4, 8, batch_first=True)

# Padded sequences: length 5, 3, 2
X = torch.zeros(3, 5, 4)  # (batch=3, max_seq=5, features=4)
X[0, :, :] = torch.randn(5, 4)  # full seq
X[1, :3, :] = torch.randn(3, 4) # length 3
X[2, :2, :] = torch.randn(2, 4) # length 2
lengths = torch.tensor([5, 3, 2])

packed = pack_padded_sequence(X, lengths, batch_first=True)
out_packed, h_n = rnn(packed)
out, _ = pad_packed_sequence(out_packed, batch_first=True)
print(out.shape)  # (3, 5, 8) -- back to padded form

Bila Hendak Menggunakan RNN Asas

RNN asas jarang digunakan dalam amalan kerana sangat terjejas oleh kecerunan yang lenyap pada jujukan yang melebihi 10–20 timestep. RNN ini terutamanya berguna untuk tujuan pendidikan dan jujukan yang sangat pendek. Untuk mana-mana aplikasi sebenar dengan jujukan yang melebihi 20 timestep, gunakan LSTM atau GRU, yang mempunyai mekanisme get yang direka khusus untuk mengekalkan maklumat merentasi jarak yang panjang. Bagi jujukan yang susunan elemennya kurang penting, seni bina Transformer sering mengatasi kedua-duanya.

# When to use each sequence model:
use_cases = {
    'Vanilla RNN (nn.RNN)':  'Short sequences (<20 steps), learning/demos',
    'LSTM':                  'Long sequences, NLP, time-series (general)',
    'GRU':                   'Similar to LSTM but faster, fewer params',
    'Transformer':           'Parallelisable, long documents, state-of-art NLP',
    'Temporal Conv (TCN)':   'Long sequences, strong parallelism, audio',
}
for model, use in use_cases.items():
    print(f'{model}: {use}')

Semakan Pantas

Uji pemahaman anda tentang konsep Pembelajaran Mesin dengan Python daripada pelajaran ini.

Imbas Kembali Pelajaran

Dalam pelajaran ini, anda telah mempelajari bahawa: RNN asas mengekalkan keadaan tersembunyi yang membawa ingatan merentasi timestep menggunakan formula h_t = tanh(W_xh * x_t + W_hh * h_{t-1} + b), pembukaan lipatan menggunakan sel yang sama pada setiap timestep dengan pemberat yang dikongsi, dan BPTT menyebarkan kecerunan kembali melalui graf yang telah dibuka lipatannya, lalu menyebabkan masalah kecerunan yang lenyap atau meletup pada jujukan panjang. Seterusnya, kita akan meneliti masalah kecerunan yang lenyap dengan lebih mendalam dan memahami sebab LSTM direka untuk menyelesaikannya.

Percuma untuk bermula

Pelajari Python dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
30
Pelajaran
120

Soalan Lazim

Adakah pelajaran “RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan” percuma?

Ya — teks penuh “RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Machine Learning Academy, tingkat taraf kepada CoddyKit PRO. Kursus Machine Learning Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan”?

Pelajar akan melaksanakan sel RNN satu langkah secara manual, mengembangkannya merentasi jujukan pendek, dan memvisualisasikan cara keadaan tersembunyi mengumpulkan konteks. Anda berlatih Machine Learning Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Machine Learning Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Machine Learning Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 1 daripada 4.

Berapa lamakah pelajaran “RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Machine Learning Academy ini?

Ya. Setiap pelajaran Machine Learning Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. RNN Asas: Keadaan Tersembunyi dan Pengembangan Jujukan
  2. Masalah Kecerunan Lenyap dalam Langkah Masa Mendalam
  3. Sel LSTM: Get Input, Lupa dan Output
  4. Jujukan-ke-Satu: Analisis Sentimen dengan LSTM
← Kembali ke Machine Learning Academy