single
Utfordring: Bygge en transformer-basert tekstklassifisierer
Sveip for å vise menyen
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 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)
Sveip for å begynne å kode
Bygg en minimal Transformer tekstklassifiserer steg for steg:
- Skriv en funksjon
tokenizesom tar en streng og returnerer en liste med små bokstaver av ordene; - Skriv en funksjon
build_vocabsom 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); - Skriv en funksjon
text_to_sequencesom 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
Takk for tilbakemeldingene dine!
single
Spør AI
Spør AI
Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår