Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Leer Challenge: Het Bouwen van een Transformer-Tekstclassificator | Toepassen van Transformers op NLP-taken
Transformers voor Natuurlijke Taalverwerking
Sectie 3. Hoofdstuk 2
single

single

bookChallenge: Het Bouwen van een Transformer-Tekstclassificator

Veeg om het menu te tonen

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

Je hebt zojuist een minimale implementatie gezien van een Transformer-gebaseerde tekstclassificator met alleen numpy en kernfunctionaliteit van Python. Deze code laat zien hoe de essentiële onderdelen van een Transformer kunnen worden samengebracht voor een tekstclassificatietaak zonder afhankelijk te zijn van deep learning-bibliotheken.

Het proces begint met het omzetten van ruwe tekst naar een formaat dat geschikt is voor berekeningen. De functie tokenize splitst de tekst in kleine letters woorden:

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

Vervolgens maakt build_vocab een mapping van elk uniek woord naar een uniek geheel getal:

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

De functie text_to_sequence zet elke invoerzinsnede om naar een sequentie van vaste lengte met woordindexen, waarbij zo nodig wordt opgevuld of afgekapt:

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

Om het model bewust te maken van de volgorde van woorden, genereert positional_encoding een matrix van sinusoïdale waarden die bij de woordembeddings kan worden opgeteld. Deze stap is cruciaal omdat, in tegenstelling tot recurrente netwerken, Transformers niet inherent sequentieel verwerken:

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

Het self-attention-mechanisme, geïmplementeerd in self_attention, stelt het model in staat het belang van elk woord te wegen in de context van de hele sequentie. Dit gebeurt door gelijkenisscores te berekenen tussen alle woordparen, de softmax-functie toe te passen om attention-gewichten te verkrijgen, en vervolgens een nieuwe representatie voor elk woord te creëren als een gewogen som van alle woorden in de sequentie:

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)

Na self-attention verwerkt een eenvoudige feed-forward-netwerk (feed_forward) de sequentie verder:

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

De functie transformer_encoder combineert deze stappen door positionele codering, self-attention en het feed-forward-netwerk achtereenvolgens toe te passen:

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

De klasse TransformerClassifier brengt alles samen. Deze initialiseert willekeurige woordembeddings, laaggewichten en positionele coderingen. In de forward-methode worden de embeddings voor elke token opgezocht, wordt het encoderblok toegepast, worden de uitkomsten gemiddeld over de sequentie (pooling), en wordt het resultaat door een laatste lineaire laag gehaald om klassekansen te produceren:

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

Aan het einde van de code zie je een voorbeeld waarbij een kleine set trainingsteksten wordt gebruikt om het vocabulaire op te bouwen en de classificator te initialiseren. Wanneer je een nieuwe zin invoert, voorspelt het model klassekansen, waarmee wordt getoond hoe de minimale Transformer-pijplijn werkt van ruwe tekst tot voorspelling:

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

Veeg om te beginnen met coderen

Bouw stap voor stap een minimale Transformer-tekstclassificator:

  1. Schrijf een functie tokenize die een string neemt en een lijst van kleine letters als woorden retourneert;
  2. Schrijf een functie build_vocab die een lijst van teksten neemt en een woordenboek retourneert dat elk uniek woord aan een geheelgetal-index koppelt (begin met indexeren vanaf 1, reserveer 0 voor padding);
  3. Schrijf een functie text_to_sequence die een tekst omzet naar een lijst van woordindices met behulp van een vocabulaire en deze opvult of afkapt tot een vaste lengte.

Test uw functies met:

  • tokenize("Hello World!") moet ["hello", "world!"] retourneren;
  • build_vocab(["Hello world", "world of NLP"]) moet een woordenboek retourneren dat woorden aan unieke indices koppelt (bijvoorbeeld {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) moet een lijst van 4 indices retourneren, indien nodig opgevuld met nullen.

Oplossing

Switch to desktopSchakel over naar desktop voor praktijkervaringGa verder vanaf waar je bent met een van de onderstaande opties
Was alles duidelijk?

Hoe kunnen we het verbeteren?

Bedankt voor je feedback!

Sectie 3. Hoofdstuk 2
single

single

Vraag AI

expand

Vraag AI

ChatGPT

Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.

some-alt