Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära Challenge: Bygga en Transformerbaserad Textklassificerare | Applying Transformers to NLP Tasks
Transformers för Naturlig Språkbehandling
Avsnitt 3. Kapitel 2
single

single

bookChallenge: Bygga en Transformerbaserad Textklassificerare

Svep för att visa menyn

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

Svep för att börja koda

Bygg en minimal Transformer-textklassificerare steg för steg:

  1. Skriv en funktion tokenize som tar en sträng och returnerar en lista med gemener av orden;
  2. Skriv en funktion build_vocab som 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);
  3. Skriv en funktion text_to_sequence som 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

Switch to desktopByt till skrivbordet för praktisk övningFortsätt där du är med ett av alternativen nedan
Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 3. Kapitel 2
single

single

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

some-alt