Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Desafio: Construindo um Classificador de Texto com Transformer | Aplicando Transformers a Tarefas de PLN
Transformers para Processamento de Linguagem Natural
Seção 3. Capítulo 2
single

single

bookDesafio: Construindo um Classificador de Texto com Transformer

Deslize para mostrar o menu

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

Você acabou de ver uma implementação mínima de um classificador de texto baseado em Transformer utilizando apenas numpy e recursos básicos do Python. Este código demonstra como as partes essenciais de um Transformer podem ser combinadas para uma tarefa de classificação de texto sem depender de bibliotecas de deep learning.

O processo começa convertendo o texto bruto em um formato adequado para computação. A função tokenize divide o texto em palavras minúsculas:

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

Em seguida, build_vocab cria um mapeamento de cada palavra única para um inteiro único:

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

A função text_to_sequence transforma cada sentença de entrada em uma sequência de índices de palavras de comprimento fixo, preenchendo ou truncando conforme necessário:

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

Para dar ao modelo consciência da ordem das palavras, positional_encoding gera uma matriz de valores senoides que pode ser somada aos embeddings das palavras. Esta etapa é crucial porque, ao contrário das redes recorrentes, Transformers não processam sequências em ordem de forma inerente:

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

O mecanismo de self-attention, implementado em self_attention, permite que o modelo avalie a importância de cada palavra no contexto de toda a sequência. Isso é feito calculando escores de similaridade entre todos os pares de palavras, aplicando a função softmax para obter pesos de atenção e, em seguida, criando uma nova representação para cada palavra como uma soma ponderada de todas as palavras da sequência:

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)

Após o self-attention, uma rede feed-forward simples (feed_forward) processa ainda mais a sequência:

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

A função transformer_encoder combina essas etapas, aplicando codificação posicional, self-attention e a rede feed-forward em sequência:

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

A classe TransformerClassifier integra tudo. Ela inicializa embeddings de palavras aleatórios, pesos das camadas e codificações posicionais. No método forward, busca os embeddings para cada token, aplica o bloco codificador, faz o pooling das saídas por média ao longo da sequência e passa o resultado por uma camada linear final para produzir as probabilidades das classes:

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

Você pode ver um exemplo ao final do código, onde um pequeno conjunto de textos de treinamento é usado para construir o vocabulário e configurar o classificador. Quando uma nova sentença é fornecida, o modelo prevê as probabilidades das classes, mostrando como o pipeline mínimo do Transformer funciona desde o texto bruto até a predição:

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

Deslize para começar a programar

Construa um classificador de texto minimalista com Transformer, passo a passo:

  1. Escreva uma função tokenize que recebe uma string e retorna uma lista de palavras em minúsculas;
  2. Escreva uma função build_vocab que recebe uma lista de textos e retorna um dicionário mapeando cada palavra única para um índice inteiro (comece a indexação em 1, reserve 0 para padding);
  3. Escreva uma função text_to_sequence que converte um texto em uma lista de índices de palavras usando um vocabulário e faz o padding/truncamento para um comprimento fixo.

Teste suas funções com:

  • tokenize("Hello World!") deve retornar ["hello", "world!"];
  • build_vocab(["Hello world", "world of NLP"]) deve retornar um dicionário mapeando palavras para índices únicos (por exemplo, {"hello": 1, "world": 2, "of": 3, "nlp": 4});
  • text_to_sequence("Hello NLP", vocab, 4) deve retornar uma lista de 4 índices, preenchida com zeros se necessário.

Solução

Switch to desktopMude para o desktop para praticar no mundo realContinue de onde você está usando uma das opções abaixo
Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 3. Capítulo 2
single

single

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

some-alt