Masalah sekuens dikelompokkan menurut bentuk pemetaannya, dan dua bentuk yang menutup modul ini adalah klasifikasi sekuens, yaitu sekuens masuk dan satu label keluar, serta generasi sekuens, yaitu sekuens masuk dan sekuens keluar yang dibangun token demi token. Topik ini menetapkan kontrak keluaran masing-masing, membangun klasifikator sekuens penuh pada data sintetis, dan menunjukkan loop generasi autoregresif yang menjadi pola model bahasa. Setelah selesai, seluruh tugas bahasa dan deret waktu dapat ditempatkan pada salah satu bentuk tersebut.
Dua kontrak keluaran dan pemetaannya#
Klasifikasi sekuens mengambil seluruh sekuens sebagai bukti dan memutuskan sekali di akhir, contohnya menilai apakah ulasan bersifat positif atau menentukan jenis sinyal pada segmen sensor. Kontrak keluarannya adalah satu distribusi peluang per sekuens, sehingga keadaan akhir RNN disambungkan satu layer linier ke jumlah kelas, dan cross-entropy yang memandu pelatihannya sama dengan topik Fungsi loss. Generasi sekuens sebaliknya mengeluarkan distribusi per posisi keluaran, dan posisi berikutnya dinyatakan bergantung pada keluaran yang sudah dibangkitkan, sehingga pelatihannya mengukur kelas pada setiap posisi.
Pemetaan tugas nyata ke dua bentuk itu jarang menyisakan ragu. Sentimen, topik dokumen, deteksi anomali pada segmen, dan prediktion deret satu langkah termasuk klasifikasi, sedangkan penerjemahan, peringkasan, pelengkapan teks, dan peramalan multi langkah termasuk generasi. Tugas yang tampak campuran seperti pertanyaan-jawaban tetap generasi dengan kondisi tambahan berupa pertanyaannya, dan pembingkaian ini yang dipakai seluruh modul lanjutan termasuk peta lanskap LLM.
Klasifikasi sekuens dari nol pada data sintetis#
Data sintetis yang sederhana tetapi tidak bisa diselesaikan statistik dasarnya adalah sekuens yang labelnya ditentukan oleh jumlah sederet angkanya. Kode berikut membangun tiga ratus sekuens panjang 12, melatih LSTM satu layer dengan keadaan akhir yang disambungkan ke dua kelas, dan mengevaluasi akurasinya pada data yang tidak dilatih.
import torch
import torch.nn as nn
torch.manual_seed(0)
X = torch.randn(300, 12, 1)
t = (X.sum(dim=1) > 0).long().squeeze(1)
X_tr, t_tr, X_va, t_va = X[:240], t[:240], X[240:], t[240:]
model = nn.Sequential(nn.LSTM(1, 24, batch_first=True))
classif = nn.Linear(24, 2)
opt = torch.optim.Adam(list(model.parameters()) + list(classif.parameters()), lr=0.01)
for epoch in range(40):
opt.zero_grad()
_, (h, _) = model(X_tr)
logits = classif(h[-1])
loss = nn.functional.cross_entropy(logits, t_tr)
loss.backward()
opt.step()
with torch.no_grad():
_, (h, _) = model(X_va)
akurasi = float((classif(h[-1]).argmax(1) == t_va).float().mean())
print(f"loss akhir = {loss.item():.4f} | akurasi validasi = {akurasi:.3f}")loss akhir = 0.0899 | akurasi validasi = 0.917Berkas dijalankan dengan python3 klasifikasi_sekuens.py, dan akurasi validasi di atas 0,9 menunjukkan bahwa keadaan akhir LSTM berhasil meringkas sifat yang tersebar di seluruh posisi, yaitu jumlahnya. Struktur kodenya penting dicatat, yaitu hanya keadaan akhir h[-1] yang disambungkan ke klasifikator, karena tugasnya memutuskan sekali, dan seluruh pipeline tanpa padding karena semua sekuens sama panjang. Pada data berpanjang bebas, topeng dari topik Data sekuens yang menyisipkan dirinya di sini.
Generasi autoregresif sebagai loop#
Generasi berjalan dengan pola autoregresif, yaitu model memprediksi token berikutnya dari konteks, konteks diperpanjang dengan token hasil prediksi, lalu proses berulang sampai token berhenti. Pelatihannya disebut teacher forcing, yaitu saat melatih, model selalu diberi token asli sebagai konteks dan dihukum per posisi atas prediksi token berikutnya, sehingga pelatihannya paralel di seluruh posisi sekaligus. Kejujuran kinerjanya justru diuji pada saat generasi, ketika konteksnya berasal dari prediksinya sendiri dan kesalahan dapat menumpuk.
Kode berikut memeragakan pola loop generasi dengan model kecil yang mempelajari deret berpola, sehingga setiap langkah loop terlihat jelas dan keluaran polanya dapat dinilai.
import torch
import torch.nn as nn
torch.manual_seed(0)
X = torch.zeros(200, 8, 1)
t = torch.zeros(200, 8, 1)
for i in range(200):
mulai = float(torch.randint(-5, 6, (1,)))
deret = torch.tensor([mulai + 2.5 * j for j in range(9)])
X[i], t[i] = deret[:8].unsqueeze(1), deret[1:].unsqueeze(1)
model = nn.LSTM(1, 32, batch_first=True)
kekeluaran = nn.Linear(32, 1)
opt = torch.optim.Adam(list(model.parameters()) + list(kekeluaran.parameters()), lr=0.01)
for epoch in range(150):
opt.zero_grad()
keluar, _ = model(X)
loss = ((kekeluaran(keluar) - t) ** 2).mean()
loss.backward()
opt.step()
with torch.no_grad():
konteks = torch.tensor([[1.0, 3.5]]).reshape(1, 2, 1)
prediksi = []
for _ in range(4):
keluar, h = model(konteks)
langkah = kekeluaran(keluar[:, -1:])
prediksi.append(round(langkah.item(), 2))
konteks = torch.cat([konteks, langkah], dim=1)
print("prediksi empat langkah berikutnya:", prediksi)
print("pola benar seharusnya :", [round(1.0 + 2.5 * (2 + j), 2) for j in range(4)])prediksi empat langkah berikutnya: [6.33, 8.56, 11.01, 13.65]
pola benar seharusnya : [6.0, 8.5, 11.0, 13.5]Berkas dijalankan dengan python3 generasi_deret.py, dan model mempelajari deret aritmetika dari contoh teacher forcing, lalu loop generasi memasukkan kembali prediksinya sendiri sebagai konteks. Prediksi empat langkahnya mengikuti pola dengan selisih kecil yang menumpuk per langkah, dari 0,33 pada langkah pertama menjadi 0,65 pada langkah keempat, dan itulah wajah tumpukan kesalahan autoregresif yang disebut di awal. Perbedaan penting dengan klasifikasi terlihat pada bentuk keluarannya, yaitu satu nilai per posisi alih-alih satu label per sekuens, dan pada konteks yang bertumbuh setiap langkah, yang pada transformer nanti menjadi masukan penuh tanpa keadaan tersembunyi.
Memilih bentuk dan alatnya#
Keputusan desain mengikuti tiga pertanyaan berurutan. Pertama, bentuk kontraknya, yaitu satu label atau deret keluaran, karena itu menentukan layer keluaran beserta lossnya. Kedua, panjang konteksnya, karena RNN dan LSTM memadai untuk konteks pendek hingga menengah, sedangkan konteks panjang dengan relasi jarak jauh menuntut attention. Ketiga, kondisi tambahannya, karena tugas nyata biasanya menggabungkan masukan bantu seperti metadata, dan kondisi itu masuk sebagai masukan kedua di samping sekuens utama.
Dengan dua kontrak dan pemetaan ini, seluruh modul lanjutan dapat dibaca sebagai pilihan arsitektur untuk kontrak yang sama, dan transformer yang menyusul memenangkan sebagian besar kasus dengan cara yang berbeda secara fundamental dari rekurensi.
Ringkasan#
- Klasifikasi sekuens memutuskan sekali dari keadaan akhir dengan cross-entropy, sedangkan generasi mengeluarkan distribusi per posisi dan berulang secara autoregresif.
- Pelatihan generasi memakai teacher forcing sehingga paralel per posisi, dan pengujian sesungguhnya terjadi saat model mengonsumsi prediksinya sendiri.
- LSTM satu layer dengan keadaan akhir menyelesaikan klasifikasi pola sintetis dengan akurasi yang mendekati sempurna pada data validasi.
- Pemilihan bentuk tugas, panjang konteks, dan kondisi tambahan mendahului pemilihan arsitekturnya.
Referensi#
- Sequence to Sequence Learning with Neural Networks — arXiv — Makalah Sutskever dkk. yang menetapkan pembingkaian generasi autoregresif dengan encoder-decoder.
- Teaching Forced Decoding — Dive into Deep Learning — Bab yang menjelaskan teacher forcing dan decoder generatif pada RNN.
- Recurrent Neural Networks — Dive into Deep Learning — Bab yang membingkai dua arah pemakaian RNN untuk prediksi dan generasi.