single
Challenge: Transformer-pohjaisen Tekstiluokittelijan Rakentaminen
Pyyhkäise näyttääksesi valikon
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)
Olet juuri nähnyt minimaalisen toteutuksen Transformer-pohjaisesta tekstiluokittelijasta käyttäen vain numpy- ja Pythonin ydintoimintoja. Tämä koodi havainnollistaa, miten Transformerin olennaiset osat voidaan yhdistää tekstinluokittelutehtävään ilman syväoppimiskirjastoja.
Prosessi alkaa muuntamalla raakateksti laskentaan sopivaan muotoon. tokenize-funktio pilkkoo tekstin pieniksi kirjaimiksi muutetuiksi sanoiksi:
def tokenize(text):
return text.lower().split()
Seuraavaksi build_vocab luo jokaiselle uniikille sanalle yksilöllisen kokonaislukumäppäyksen:
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
text_to_sequence-funktio muuntaa jokaisen syötelauseen kiinteän mittaiseksi sananindeksijonoksi, täyttäen tai katkaisten tarpeen mukaan:
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
Jotta malli huomioi sanajärjestyksen, positional_encoding tuottaa sinimuotoisten arvojen matriisin, joka voidaan lisätä sanaupotuksiin. Tämä vaihe on olennainen, koska toisin kuin rekurrenttiverkot, Transformerit eivät käsittele sekvenssejä järjestyksessä luonnostaan:
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-mekanismi, joka on toteutettu funktiossa self_attention, mahdollistaa mallin painottavan jokaisen sanan merkitystä koko sekvenssin kontekstissa. Tämä tehdään laskemalla samankaltaisuuspisteet kaikkien sanaparien välillä, käyttämällä softmax-funktiota painojen saamiseksi ja muodostamalla uusi esitys jokaiselle sanalle painotettuna summana kaikista sekvenssin sanoista:
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)
Self-attentionin jälkeen yksinkertainen feed-forward-verkko (feed_forward) jatkokäsittelee sekvenssiä:
def feed_forward(X, W1, b1, W2, b2):
return np.maximum(0, X @ W1 + b1) @ W2 + b2
transformer_encoder-funktio yhdistää nämä vaiheet, lisäten positionaalisen koodauksen, self-attentionin ja feed-forward-verkon peräkkäin:
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
TransformerClassifier-luokka kokoaa kaiken yhteen. Se alustaa satunnaiset sanaupotukset, kerrospainot ja positionaaliset koodaukset. forward-metodissa se hakee upotukset jokaiselle tokenille, käyttää enkooderilohkoa, poolaa tulokset ottamalla keskiarvon sekvenssin yli ja syöttää tuloksen lopullisen lineaarikerroksen läpi tuottaen luokkien todennäköisyydet:
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
Voit nähdä esimerkin koodin lopussa, jossa pieni joukko koulutustekstejä käytetään sanaston rakentamiseen ja luokittelijan alustamiseen. Kun syötät uuden lauseen, malli ennustaa luokkien todennäköisyydet, havainnollistaen kuinka minimaalinen Transformer-putki toimii raakatekstistä ennusteeseen:
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)
Pyyhkäise aloittaaksesi koodauksen
Rakenna vaiheittain minimaalinen Transformer-tekstiluokittelija:
- Kirjoita funktio
tokenize, joka ottaa merkkijonon ja palauttaa listan pienaakkosista sanoista; - Kirjoita funktio
build_vocab, joka ottaa listan tekstejä ja palauttaa sanakirjan, jossa jokainen uniikki sana on yhdistetty kokonaislukuindeksiin (aloita indeksointi arvosta 1, varaa 0 täydennykselle); - Kirjoita funktio
text_to_sequence, joka muuntaa tekstin sanalistaksi käyttäen sanastoa ja täyttää/katkaisee listan kiinteään pituuteen.
Testaa funktiosi seuraavasti:
tokenize("Hello World!")palauttaa["hello", "world!"];build_vocab(["Hello world", "world of NLP"])palauttaa sanakirjan, jossa sanat on yhdistetty uniikkeihin indekseihin (esim.{"hello": 1, "world": 2, "of": 3, "nlp": 4});text_to_sequence("Hello NLP", vocab, 4)palauttaa listan, jossa on 4 indeksiä ja tarvittaessa täydennetty nollilla.
Ratkaisu
Kiitos palautteestasi!
single
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme