Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Challenge: Opbygning af en Transformer Tekstklassifikator | Anvendelse af Transformers til NLP-opgaver
Transformers til Naturlig Sprogbehandling
Sektion 3. Kapitel 2
single

single

bookChallenge: Opbygning af en Transformer Tekstklassifikator

Stryg for at vise menuen

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

Du har netop set en minimal implementering af en Transformer-baseret tekstklassifikator, der kun anvender numpy og grundlæggende Python-funktioner. Denne kode demonstrerer, hvordan de væsentlige dele af en Transformer kan sammensættes til en tekstklassifikationsopgave uden brug af dybe læringsbiblioteker.

Processen starter med at konvertere rå tekst til et format, der egner sig til beregning. Funktionen tokenize opdeler teksten i små bogstaver:

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

Dernæst opretter build_vocab en mapping fra hvert unikke ord til et unikt heltal:

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

Funktionen text_to_sequence omdanner hver indgangssætning til en sekvens af ordindekser med fast længde, hvor der tilføjes padding eller trunkeres efter behov:

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

For at give modellen bevidsthed om ordstillingen genererer positional_encoding en matrix af sinusformede værdier, der kan lægges til ordembeddingerne. Dette trin er afgørende, fordi Transformers ikke automatisk bearbejder sekvenser i rækkefølge i modsætning til rekurrente netværk:

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-mekanismen, implementeret i self_attention, gør det muligt for modellen at vægte betydningen af hvert ord i forhold til hele sekvensen. Dette opnås ved at beregne lighedsscorer mellem alle ordpar, anvende softmax-funktionen for at opnå attention-vægte og derefter skabe en ny repræsentation for hvert ord som en vægtet sum af alle ordene i sekvensen:

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)

Efter self-attention bearbejdes sekvensen yderligere af et simpelt feed-forward-netværk (feed_forward):

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

Funktionen transformer_encoder kombinerer disse trin ved at anvende positionskodning, self-attention og feed-forward-netværket i rækkefølge:

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

Klassen TransformerClassifier samler det hele. Den initialiserer tilfældige ordembeddinger, lagvægtninger og positionskodninger. I forward-metoden slår den embedding op for hvert token, anvender encoder-blokken, pooler outputtet ved at tage gennemsnittet over sekvensen og sender resultatet gennem et sidste lineært lag for at producere klasse-sandsynligheder:

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

Du kan se et eksempel sidst i koden, hvor et lille sæt træningstekster bruges til at opbygge ordforrådet og opsætte klassifikatoren. Når du indtaster en ny sætning, forudsiger modellen klasse-sandsynligheder, hvilket viser, hvordan den minimale Transformer-pipeline fungerer fra rå tekst til forudsigelse:

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)
Opgave

Swipe to start coding

Byg en minimal Transformer-tekstklassifikator trin for trin:

  1. Skriv en funktion tokenize, der tager en streng og returnerer en liste af små bogstaverede ord;
  2. Skriv en funktion build_vocab, der tager en liste af tekster og returnerer et ordbogsobjekt, som kortlægger hvert unikke ord til et heltalsindeks (start indeksering fra 1, reserver 0 til padding);
  3. Skriv en funktion text_to_sequence, der konverterer en tekst til en liste af ordindekser ved brug af et ordforråd og tilføjer/afkorter til en fast længde.

Test dine funktioner med:

  • tokenize("Hello World!") skal returnere ["hello", "world!"];
  • build_vocab(["Hello world", "world of NLP"]) skal returnere et ordbogsobjekt, der kortlægger ord til unikke indekser (f.eks. {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) skal returnere en liste med 4 indekser, udfyldt med nuller hvis nødvendigt.

Løsning

Switch to desktopSkift til skrivebord for at øve i den virkelige verdenFortsæt der, hvor du er, med en af nedenstående muligheder
Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 3. Kapitel 2
single

single

Spørg AI

expand

Spørg AI

ChatGPT

Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat

some-alt