Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Challenge: Transformer-pohjaisen Tekstiluokittelijan Rakentaminen | Transformereiden Soveltaminen NLP-tehtäviin
Transformerit Luonnollisen Kielen Käsittelyssä
Osio 3. Luku 2
single

single

bookChallenge: Transformer-pohjaisen Tekstiluokittelijan Rakentaminen

Pyyhkäise näyttääksesi valikon

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
import numpy as np # Simple tokenizer: splits text into lowercase words def tokenize(text): return text.lower().split() # Build vocabulary from training texts def build_vocab(texts): vocab = {} idx = 1 # 0 reserved for padding for text in texts: for word in tokenize(text): if word not in vocab: vocab[word] = idx idx += 1 return vocab # Convert text to sequence of word indices def text_to_sequence(text, vocab, max_len): seq = [vocab.get(word, 0) for word in tokenize(text)] if len(seq) < max_len: seq += [0] * (max_len - len(seq)) else: seq = seq[:max_len] return np.array(seq) # Sinusoidal positional encoding def positional_encoding(seq_len, d_model): pos = np.arange(seq_len)[:, np.newaxis] i = np.arange(d_model)[np.newaxis, :] angle_rates = 1 / np.power(10000, (2 * (i // 2)) / np.float32(d_model)) angle_rads = pos * angle_rates pe = np.zeros((seq_len, d_model)) pe[:, 0::2] = np.sin(angle_rads[:, 0::2]) pe[:, 1::2] = np.cos(angle_rads[:, 1::2]) return pe # Simple self-attention layer def self_attention(X): d_k = X.shape[-1] Q = X K = X V = X scores = Q @ K.T / np.sqrt(d_k) weights = softmax(scores) return weights @ V def softmax(x): e_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) return e_x / np.sum(e_x, axis=-1, keepdims=True) # Feed-forward layer def feed_forward(X, W1, b1, W2, b2): return np.maximum(0, X @ W1 + b1) @ W2 + b2 # Minimal Transformer encoder block def transformer_encoder(X, pe, W1, b1, W2, b2): X_pe = X + pe attn_out = self_attention(X_pe) ff_out = feed_forward(attn_out, W1, b1, W2, b2) return ff_out # Classifier class TransformerClassifier: def __init__(self, vocab_size, d_model, max_len, num_classes): self.d_model = d_model self.max_len = max_len self.embeddings = np.random.randn(vocab_size + 1, d_model) * 0.01 self.W1 = np.random.randn(d_model, d_model) * 0.01 self.b1 = np.zeros(d_model) self.W2 = np.random.randn(d_model, d_model) * 0.01 self.b2 = np.zeros(d_model) self.Wc = np.random.randn(d_model, num_classes) * 0.01 self.bc = np.zeros(num_classes) self.pe = positional_encoding(max_len, d_model) def forward(self, x_seq): X = self.embeddings[x_seq] encoded = transformer_encoder(X, self.pe, self.W1, self.b1, self.W2, self.b2) pooled = np.mean(encoded, axis=0) # Simple mean pooling logits = pooled @ self.Wc + self.bc probs = softmax(logits) return probs # Example usage: texts = ["I love machine learning", "Transformers are powerful", "Deep learning is cool"] labels = [0, 1, 0] # 2 classes: 0, 1 vocab = build_vocab(texts) max_len = 6 d_model = 8 num_classes = 2 clf = TransformerClassifier(len(vocab), d_model, max_len, num_classes) # Predict class probabilities for a new text test_text = "I love transformers" test_seq = text_to_sequence(test_text, vocab, max_len) probs = clf.forward(test_seq) print("Predicted class probabilities:", probs)
copy

Olet juuri nähnyt minimaalisen toteutuksen Transformer-pohjaisesta tekstiluokittelijasta käyttäen vain numpy- ja Pythonin ydintoimintoja. Tämä koodi havainnollistaa, miten Transformerin olennaiset osat voidaan yhdistää tekstinluokittelutehtävään ilman syväoppimiskirjastoja.

Prosessi alkaa muuntamalla raakateksti laskentaan sopivaan muotoon. tokenize-funktio pilkkoo tekstin pieniksi kirjaimiksi muutetuiksi sanoiksi:

def tokenize(text):
    return text.lower().split()

Seuraavaksi build_vocab luo jokaiselle uniikille sanalle yksilöllisen kokonaislukumäppäyksen:

def build_vocab(texts):
    vocab = {}
    idx = 1  # 0 reserved for padding
    for text in texts:
        for word in tokenize(text):
            if word not in vocab:
                vocab[word] = idx
                idx += 1
    return vocab

text_to_sequence-funktio muuntaa jokaisen syötelauseen kiinteän mittaiseksi sananindeksijonoksi, täyttäen tai katkaisten tarpeen mukaan:

def text_to_sequence(text, vocab, max_len):
    seq = [vocab.get(word, 0) for word in tokenize(text)]
    if len(seq) < max_len:
        seq += [0] * (max_len - len(seq))
    else:
        seq = seq[:max_len]
    return seq

Jotta malli huomioi sanajärjestyksen, positional_encoding tuottaa sinimuotoisten arvojen matriisin, joka voidaan lisätä sanaupotuksiin. Tämä vaihe on olennainen, koska toisin kuin rekurrenttiverkot, Transformerit eivät käsittele sekvenssejä järjestyksessä luonnostaan:

def positional_encoding(seq_len, d_model):
    pos = np.arange(seq_len)[:, np.newaxis]
    i = np.arange(d_model)[np.newaxis, :]
    angle_rates = 1 / np.power(10000, (2 * (i // 2)) / np.float32(d_model))
    angle_rads = pos * angle_rates
    pe = np.zeros((seq_len, d_model))
    pe[:, 0::2] = np.sin(angle_rads[:, 0::2])
    pe[:, 1::2] = np.cos(angle_rads[:, 1::2])
    return pe

Self-attention-mekanismi, joka on toteutettu funktiossa self_attention, mahdollistaa mallin painottavan jokaisen sanan merkitystä koko sekvenssin kontekstissa. Tämä tehdään laskemalla samankaltaisuuspisteet kaikkien sanaparien välillä, käyttämällä softmax-funktiota painojen saamiseksi ja muodostamalla uusi esitys jokaiselle sanalle painotettuna summana kaikista sekvenssin sanoista:

def self_attention(X):
    d_k = X.shape[-1]
    Q = X
    K = X
    V = X
    scores = Q @ K.T / np.sqrt(d_k)
    weights = softmax(scores)
    return weights @ V

def softmax(x):
    e_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
    return e_x / np.sum(e_x, axis=-1, keepdims=True)

Self-attentionin jälkeen yksinkertainen feed-forward-verkko (feed_forward) jatkokäsittelee sekvenssiä:

def feed_forward(X, W1, b1, W2, b2):
    return np.maximum(0, X @ W1 + b1) @ W2 + b2

transformer_encoder-funktio yhdistää nämä vaiheet, lisäten positionaalisen koodauksen, self-attentionin ja feed-forward-verkon peräkkäin:

def transformer_encoder(X, pe, W1, b1, W2, b2):
    X_pe = X + pe
    attn_out = self_attention(X_pe)
    ff_out = feed_forward(attn_out, W1, b1, W2, b2)
    return ff_out

TransformerClassifier-luokka kokoaa kaiken yhteen. Se alustaa satunnaiset sanaupotukset, kerrospainot ja positionaaliset koodaukset. forward-metodissa se hakee upotukset jokaiselle tokenille, käyttää enkooderilohkoa, poolaa tulokset ottamalla keskiarvon sekvenssin yli ja syöttää tuloksen lopullisen lineaarikerroksen läpi tuottaen luokkien todennäköisyydet:

class TransformerClassifier:
    def __init__(self, vocab_size, d_model, max_len, num_classes):
        self.d_model = d_model
        self.max_len = max_len
        self.embeddings = np.random.randn(vocab_size + 1, d_model) * 0.01
        self.W1 = np.random.randn(d_model, d_model) * 0.01
        self.b1 = np.zeros(d_model)
        self.W2 = np.random.randn(d_model, d_model) * 0.01
        self.b2 = np.zeros(d_model)
        self.Wc = np.random.randn(d_model, num_classes) * 0.01
        self.bc = np.zeros(num_classes)
        self.pe = positional_encoding(max_len, d_model)

    def forward(self, x_seq):
        X = self.embeddings[x_seq]
        encoded = transformer_encoder(X, self.pe, self.W1, self.b1, self.W2, self.b2)
        pooled = np.mean(encoded, axis=0)  # Simple mean pooling
        logits = pooled @ self.Wc + self.bc
        probs = softmax(logits)
        return probs

Voit nähdä esimerkin koodin lopussa, jossa pieni joukko koulutustekstejä käytetään sanaston rakentamiseen ja luokittelijan alustamiseen. Kun syötät uuden lauseen, malli ennustaa luokkien todennäköisyydet, havainnollistaen kuinka minimaalinen Transformer-putki toimii raakatekstistä ennusteeseen:

texts = ["I love machine learning", "Transformers are powerful", "Deep learning is cool"]
labels = [0, 1, 0]  # 2 classes: 0, 1
vocab = build_vocab(texts)
max_len = 6
d_model = 8
num_classes = 2

clf = TransformerClassifier(len(vocab), d_model, max_len, num_classes)

test_text = "I love transformers"
test_seq = text_to_sequence(test_text, vocab, max_len)
probs = clf.forward(test_seq)
print("Predicted class probabilities:", probs)
Tehtävä

Pyyhkäise aloittaaksesi koodauksen

Rakenna vaiheittain minimaalinen Transformer-tekstiluokittelija:

  1. Kirjoita funktio tokenize, joka ottaa merkkijonon ja palauttaa listan pienaakkosista sanoista;
  2. Kirjoita funktio build_vocab, joka ottaa listan tekstejä ja palauttaa sanakirjan, jossa jokainen uniikki sana on yhdistetty kokonaislukuindeksiin (aloita indeksointi arvosta 1, varaa 0 täydennykselle);
  3. Kirjoita funktio text_to_sequence, joka muuntaa tekstin sanalistaksi käyttäen sanastoa ja täyttää/katkaisee listan kiinteään pituuteen.

Testaa funktiosi seuraavasti:

  • tokenize("Hello World!") palauttaa ["hello", "world!"];
  • build_vocab(["Hello world", "world of NLP"]) palauttaa sanakirjan, jossa sanat on yhdistetty uniikkeihin indekseihin (esim. {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) palauttaa listan, jossa on 4 indeksiä ja tarvittaessa täydennetty nollilla.

Ratkaisu

Switch to desktopVaihda työpöytään todellista harjoitusta vartenJatka siitä, missä olet käyttämällä jotakin alla olevista vaihtoehdoista
Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 3. Luku 2
single

single

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

some-alt