Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Utfordring: Bygge en transformer-basert tekstklassifisierer | Anvendelse av Transformers på NLP-oppgaver
Transformers for Naturlig Språkprosessering
Seksjon 3. Kapittel 2
single

single

bookUtfordring: Bygge en transformer-basert tekstklassifisierer

Sveip for å vise menyen

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 nettopp sett en minimal implementasjon av en Transformer-basert tekstklassifiserer ved bruk av kun numpy og grunnleggende Python-funksjoner. Denne koden viser hvordan de essensielle delene av en Transformer kan settes sammen for en tekstklassifiseringsoppgave uten å være avhengig av dyp læringsbiblioteker.

Prosessen starter med å konvertere rå tekst til et format som egner seg for beregning. Funksjonen tokenize deler teksten opp i små bokstaver og ord:

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

Deretter lager build_vocab en mapping fra hvert unike ord til et unikt heltall:

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

Funksjonen text_to_sequence gjør hver inndatatekst om til en sekvens av ordindekser med fast lengde, og fyller ut eller kutter etter 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 å gi modellen bevissthet om ordrekkefølge, genererer positional_encoding en matrise av sinusverdier som kan legges til ordembeddingene. Dette steget er avgjørende fordi, i motsetning til rekurrente nettverk, behandler ikke Transformere sekvenser i rekkefølge:

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

Selvoppmerksomhetsmekanismen, implementert i self_attention, gjør det mulig for modellen å vekte viktigheten av hvert ord i konteksten av hele sekvensen. Dette oppnås ved å beregne likhetspoeng mellom alle ordpar, bruke softmax-funksjonen for å få oppmerksomhetsvekter, og deretter lage en ny representasjon for hvert ord som en vektet sum av 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)

Etter selvoppmerksomhet bearbeides sekvensen videre av et enkelt feed-forward-nettverk (feed_forward):

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

Funksjonen transformer_encoder kombinerer disse stegene, og anvender posisjonskoding, selvoppmerksomhet og feed-forward-nettverk i rekkefø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 binder alt sammen. Den initialiserer tilfeldige ordembeddinger, lagvekter og posisjonskodinger. I forward-metoden slår den opp embedding for hver token, bruker encoder-blokken, samler utgangene ved å ta gjennomsnittet over sekvensen, og sender resultatet gjennom et siste lineært lag for å produsere klassesannsynligheter:

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 på slutten av koden der et lite sett med treningstekster brukes til å bygge vokabularet og sette opp klassifisereren. Når du gir inn en ny setning, predikerer modellen klassesannsynligheter, og viser hvordan den minimale Transformer-pipelinen fungerer fra rå tekst til prediksjon:

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

Sveip for å begynne å kode

Bygg en minimal Transformer tekstklassifiserer steg for steg:

  1. Skriv en funksjon tokenize som tar en streng og returnerer en liste med små bokstaver av ordene;
  2. Skriv en funksjon build_vocab som tar en liste med tekster og returnerer en ordbok som kartlegger hvert unike ord til et heltallsindeks (start indeksering fra 1, reserver 0 for padding);
  3. Skriv en funksjon text_to_sequence som konverterer en tekst til en liste med ordindekser ved bruk av et vokabular og padder/trunkerer til en fast lengde.

Test funksjonene dine med:

  • tokenize("Hello World!") skal returnere ["hello", "world!"];
  • build_vocab(["Hello world", "world of NLP"]) skal returnere en ordbok som kartlegger ord til unike indekser (for eksempel, {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) skal returnere en liste med 4 indekser, padet med nuller om nødvendig.

Løsning

Switch to desktopBytt til skrivebordet for virkelighetspraksisFortsett der du er med et av alternativene nedenfor
Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 3. Kapittel 2
single

single

Spør AI

expand

Spør AI

ChatGPT

Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår

some-alt