single
Challenge: Opbygning af en Transformer Tekstklassifikator
Stryg for at vise menuen
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import 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)
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)
Swipe to start coding
Byg en minimal Transformer-tekstklassifikator trin for trin:
- Skriv en funktion
tokenize, der tager en streng og returnerer en liste af små bogstaverede ord; - 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); - 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
Tak for dine kommentarer!
single
Spørg AI
Spørg AI
Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat