single
チャレンジ:トランスフォーマーによるテキスト分類器の構築
メニューを表示するにはスワイプしてください
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)
最小限の実装による、numpyとコアなPython機能のみを用いたTransformerベースのテキスト分類器の例です。このコードは、ディープラーニングライブラリに依存せずに、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はサイン波状の値からなる行列を生成し、単語埋め込みに加算します。このステップは、リカレントネットワークとは異なり、Transformerは本来シーケンスを順序通りに処理しないため重要です。
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で実装される自己注意機構は、シーケンス全体の文脈における各単語の重要度をモデルが重み付けできるようにします。これは、全単語ペア間の類似度スコアを計算し、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)
自己注意の後、シンプルなフィードフォワードネットワーク(feed_forward)がシーケンスをさらに処理します。
def feed_forward(X, W1, b1, W2, b2):
return np.maximum(0, X @ W1 + b1) @ W2 + b2
transformer_encoder関数は、位置エンコーディング、自己注意、フィードフォワードネットワークを順に適用してこれらのステップをまとめます。
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メソッドで各トークンの埋め込みを参照、エンコーダーブロックを適用、シーケンス全体で平均プーリングし、最終線形層を通してクラス確率を出力します。
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
コード末尾の例では、小さな訓練テキストセットから語彙を構築し、分類器をセットアップしています。新しい文を入力すると、モデルはクラス確率を予測し、最小限の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テキスト分類器を段階的に構築します:
- 文字列を受け取り、小文字の単語リストを返す関数
tokenizeの作成; - テキストのリストを受け取り、各ユニークな単語を整数インデックスにマッピングする辞書を返す関数
build_vocabの作成(インデックスは1から開始し、0はパディング用に予約); - テキストを語彙を用いて単語インデックスのリストに変換し、固定長にパディングまたは切り詰める関数
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つのインデックスのリストを返す。
解答
フィードバックありがとうございます!
single
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください