Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Challenge: Building a Transformer Text Classifier | Застосування трансформерів до завдань обробки природної мови
Трансформери для обробки природної мови
Секція 3. Розділ 2
single

single

bookChallenge: Building a Transformer Text Classifier

Свайпніть щоб показати меню

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

Ви щойно побачили мінімальну реалізацію текстового класифікатора на основі Transformer, використовуючи лише numpy та базові можливості Python. Цей код демонструє, як основні частини Transformer можна об'єднати для задачі класифікації тексту без використання бібліотек глибокого навчання.

Процес починається з перетворення сирого тексту у формат, придатний для обчислень. Функція tokenize розбиває текст на слова у нижньому регістрі:

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

Далі build_vocab створює відображення кожного унікального слова у унікальне ціле число:

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 перетворює кожне вхідне речення у послідовність індексів слів фіксованої довжини, додаючи паддінг або обрізаючи за потреби:

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

Щоб надати моделі інформацію про порядок слів, positional_encoding генерує матрицю синусоїдальних значень, яку можна додати до ембеддінгів слів. Цей крок є ключовим, оскільки, на відміну від рекурентних мереж, Transformers не обробляють послідовності по порядку:

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, реалізований у self_attention, дозволяє моделі визначати важливість кожного слова у контексті всієї послідовності. Це досягається шляхом обчислення коефіцієнтів схожості між усіма парами слів, застосуванням функції softmax для отримання ваг уваги, а потім створення нового представлення для кожного слова як зваженої суми всіх слів у послідовності:

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-attention проста feed-forward мережа (feed_forward) додатково обробляє послідовність:

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

Функція transformer_encoder об'єднує ці кроки, застосовуючи позиційне кодування, self-attention та feed-forward мережу послідовно:

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 поєднує все разом. Він ініціалізує випадкові ембеддінги слів, ваги шарів та позиційні кодування. У методі forward здійснюється пошук ембеддінгів для кожного токена, застосовується encoder-блок, результати агрегуються шляхом усереднення по послідовності, а потім передаються через фінальний лінійний шар для отримання ймовірностей класів:

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

В кінці коду наведено приклад, де невеликий набір навчальних текстів використовується для побудови словника та налаштування класифікатора. Коли ви вводите нове речення, модель прогнозує ймовірності класів, демонструючи, як мінімальний pipeline Transformer працює від сирого тексту до передбачення:

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)
Завдання

Проведіть, щоб почати кодувати

Побудова мінімального текстового класифікатора на основі Transformer крок за кроком:

  1. Написати функцію tokenize, яка приймає рядок і повертає список слів у нижньому регістрі;
  2. Написати функцію build_vocab, яка приймає список текстів і повертає словник, що відображає кожне унікальне слово у ціле число-індекс (нумерація починається з 1, 0 зарезервовано для паддінгу);
  3. Написати функцію text_to_sequence, яка перетворює текст у список індексів слів за допомогою словника та доповнює/обрізає до фіксованої довжини.

Перевірте свої функції за допомогою:

  • tokenize("Hello World!") має повернути ["hello", "world!"];
  • build_vocab(["Hello world", "world of NLP"]) має повернути словник, що відображає слова у унікальні індекси (наприклад, {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) має повернути список з 4 індексів, доповнений нулями за потреби.

Рішення

Switch to desktopПерейдіть на комп'ютер для реальної практикиПродовжуйте з того місця, де ви зупинились, використовуючи один з наведених нижче варіантів
Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 3. Розділ 2
single

single

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

some-alt