はじめに
現代のLLMはすべてTransformerアーキテクチャをベースにしています。E資格の試験でも頻出ですが、「理論は知っているが実装はしたことがない」という方が多いです。今回はシンプルなAttention機構を実装して、仕組みを体で理解していきます。
Self-Attentionの仕組み
Self-Attentionは「文中の各単語が他のすべての単語にどれだけ注目すべきか」を計算する仕組みです。計算には3つの行列(Query・Key・Value)を使います。
Attention(Q, K, V) = softmax(QK^T / √d_k) × V という式で表されます。QとKの内積で「どれだけ関連しているか」のスコアを計算し、Vで重み付けして情報を集約します。
NumPyでSelf-Attentionを実装
import numpy as np
def self_attention(Q, K, V):
"""
Self-Attentionの実装
Q, K, V: shape (seq_len, d_k)
"""
d_k = Q.shape[-1]
# スコアの計算: QK^T / sqrt(d_k)
scores = np.matmul(Q, K.T) / np.sqrt(d_k)
# Softmaxで確率に変換
def softmax(x):
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / np.sum(exp_x, axis=-1, keepdims=True)
attention_weights = softmax(scores)
# Valueで重み付け
output = np.matmul(attention_weights, V)
return output, attention_weights
# 簡単な例で試す
np.random.seed(42)
seq_len = 5 # 文の長さ(単語数)
d_k = 8 # 次元数
Q = np.random.randn(seq_len, d_k)
K = np.random.randn(seq_len, d_k)
V = np.random.randn(seq_len, d_k)
output, weights = self_attention(Q, K, V)
print(f'入力 shape: {Q.shape}')
print(f'出力 shape: {output.shape}')
print(f'Attention重み(各単語が他の単語にどれだけ注目するか):')
print(weights.round(3))
PyTorchでMulti-Head Attentionを実装
import torch
import torch.nn as nn
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
self.num_heads = num_heads
self.d_k = d_model // num_heads
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model)
def split_heads(self, x, batch_size):
x = x.view(batch_size, -1, self.num_heads, self.d_k)
return x.transpose(1, 2) # (batch, heads, seq, d_k)
def forward(self, x):
batch_size = x.size(0)
Q = self.split_heads(self.W_q(x), batch_size)
K = self.split_heads(self.W_k(x), batch_size)
V = self.split_heads(self.W_v(x), batch_size)
# Attention計算
scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.d_k ** 0.5)
weights = torch.softmax(scores, dim=-1)
out = torch.matmul(weights, V)
# ヘッドを結合
out = out.transpose(1, 2).contiguous()
out = out.view(batch_size, -1, self.num_heads * self.d_k)
return self.W_o(out)
# 動作確認
d_model = 64
num_heads = 8
batch_size = 2
seq_len = 10
mha = MultiHeadAttention(d_model, num_heads)
x = torch.randn(batch_size, seq_len, d_model)
output = mha(x)
print(f'入力 shape: {x.shape}')
print(f'出力 shape: {output.shape}') # 同じshapeになるはず
なぜ「Multi-Head」なのか
1つのAttentionだけでは「1つの視点」からしか文脈を捉えられません。複数のヘッドを使うことで「文法的な関係」「意味的な関係」「指示関係」など複数の視点から並行して注目関係を学習できます。
まとめ
TransformerのSelf-AttentionはQ・K・Vの行列演算で「どの単語に注目するか」を動的に計算します。実装してみると「結局は行列の掛け算+Softmax」というシンプルな仕組みだとわかります。E資格ではこの仕組みを問う問題が出るため、コードで理解しておくと記憶に残りやすいです。
📌 プログラミング・AI学習のおすすめスクール
- 資格と仕事に強い個人レッスン → 【Winスクール】プログラミング・AI講座

※本記事にはアフィリエイトリンクが含まれます。


コメント