single
Challenge: Bygga en Transformerbaserad Textklassificerare
Svep för att visa menyn
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 precis sett en minimal implementation av en Transformer-baserad textklassificerare med endast numpy och grundläggande Python-funktioner. Denna kod visar hur de väsentliga delarna av en Transformer kan sättas ihop för en textklassificeringsuppgift utan att använda djupinlärningsbibliotek.
Processen börjar med att omvandla råtext till ett format som är lämpligt för beräkning. Funktionen tokenize delar upp texten i små bokstäver:
def tokenize(text):
return text.lower().split()
Därefter skapar build_vocab en mappning från varje unikt ord till ett 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 omvandlar varje inmatad mening till en sekvens av ordindex med fast längd, där den fyller ut eller trunkerar vid 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
För att ge modellen medvetenhet om ordningen på orden genererar positional_encoding en matris av sinusformade värden som kan adderas till ordembeddingarna. Detta steg är avgörande eftersom, till skillnad från rekurrenta nätverk, hanterar Transformers inte sekvenser i ordning per automatik:
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
Självuppmärksamhetsmekanismen, implementerad i self_attention, gör det möjligt för modellen att väga vikten av varje ord i kontexten av hela sekvensen. Detta uppnås genom att beräkna likhetspoäng mellan alla ordpar, använda funktionen softmax för att få uppmärksamhetsvikter och sedan skapa en ny representation för varje ord som en viktad summa av alla ord 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 självuppmärksamheten bearbetar ett enkelt feed-forward-nätverk (feed_forward) sekvensen vidare:
def feed_forward(X, W1, b1, W2, b2):
return np.maximum(0, X @ W1 + b1) @ W2 + b2
Funktionen transformer_encoder kombinerar dessa steg genom att applicera positionskodning, självuppmärksamhet och feed-forward-nätverk i följd:
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 ihop allt. Den initierar slumpmässiga ordembeddingar, lager-vikter och positionskodningar. I metoden forward slår den upp embeddingar för varje token, applicerar encoder-blocket, poolar utdata genom att ta medelvärdet över sekvensen och skickar resultatet genom ett sista linjärt lager för att producera klass-sannolikheter:
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 ett exempel i slutet av koden där en liten uppsättning träningstexter används för att bygga vokabulären och sätta upp klassificeraren. När du matar in en ny mening förutspår modellen klass-sannolikheter, vilket visar hur det minimala Transformer-flödet fungerar från råtext till prediktion:
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)
Svep för att börja koda
Bygg en minimal Transformer-textklassificerare steg för steg:
- Skriv en funktion
tokenizesom tar en sträng och returnerar en lista med gemener av orden; - Skriv en funktion
build_vocabsom tar en lista av texter och returnerar en ordbok som mappar varje unikt ord till ett heltalsindex (börja indexera från 1, reservera 0 för padding); - Skriv en funktion
text_to_sequencesom konverterar en text till en lista av ordindex med hjälp av ett ordförråd och fyller ut eller trunkerar till en fast längd.
Testa dina funktioner med:
tokenize("Hello World!")ska returnera["hello", "world!"];build_vocab(["Hello world", "world of NLP"])ska returnera en ordbok som mappar ord till unika index (t.ex.{"hello": 1, "world": 2, "of": 3, "nlp": 4});text_to_sequence("Hello NLP", vocab, 4)ska returnera en lista med 4 index, utfylld med nollor om det behövs.
Lösning
Tack för dina kommentarer!
single
Fråga AI
Fråga AI
Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal