1 サブワードトークン化(subword tokenization)について説明し、現代の言語モデルにおいて単語レベルや文字レベルのトークン化よりも好まれる理由を述べてください。
サブワードトークン化(subword tokenization)は、完全な単語や個別の文字単位ではなく、可変長の形態素チャンクや頻度ベースの部分文字列(例: 'un'、'break'、'able')にテキストを分割するハイブリッドなテキスト分割手法です。Byte-Pair Encoding(BPE)、WordPiece、Unigram LMなどのアルゴリズムは、学習コーパスから固定サイズの語彙(ボキャブラリ)を学習します。頻出単語は単一のトークンとしてそのまま保持され、低頻度語や未知語は既知のサブワード単位に分解されます。
現代の言語モデルでサブワードトークン化が好まれる理由は、語彙サイズ、系列長(シーケンス長)、および未知語(OOV: out-of-vocabulary)に対する堅牢性のバランスが取れているためです。純粋な単語レベルのトークン化では、語彙サイズが過度に肥大化し(埋め込み行列が巨大化する原因になります)、それでもなお未知のトークンが汎用的な '[UNK]' トークンにマッピングされる問題が生じます。逆に、純粋な文字レベルのトークン化ではOOVの問題は解消されるものの、系列長が非常に長くなり、アテンション機構の計算量が劇的に増加する(系列長の2乗でスケールする)うえ、トークンあたりの意味密度が希薄化します。サブワードトークン化は、系列長を扱いやすい長さに抑え、語彙サイズを実用的な範囲(通常32k〜128kトークン)に保ち、さらに(バイトレベルのフォールバックと組み合わせることで)OOV率をゼロにできるため、最適なトレードオフを実現します。
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('gpt2')
text = 'unbelievable'
tokens = tokenizer.tokenize(text)
token_ids = tokenizer.encode(text)
print('Tokens:', tokens)
print('Token IDs:', token_ids)
AI コーチを使ってこの質問に答えてみる
2 静的単語埋め込み(static word embeddings)、コンテキストを考慮した埋め込み(contextual embeddings)、およびTransformerの隠れ状態(hidden states)の違いを説明してください。
静的単語埋め込み、コンテキストを考慮した埋め込み、およびTransformerの隠れ状態は、テキスト表現が意味や構文の文脈をどのように捉えるかという技術的進化の各段階を表しています。
1. 静的単語埋め込み(例: Word2Vec、GloVe、FastText): 文中の文脈に関係なく、語彙内の各トークンに対して単一の固定ベクトルを割り当てます。この手法では、「bank」(川の堤防 vs. 金融機関の銀行)や「apple」(果物 vs. テクノロジー企業)のような多義語であっても、静的なルックアップテーブルに依存しているため、あらゆる文脈で全く同じベクトル表現が割り当てられます。
2. コンテキストを考慮した埋め込み(例: 初期のELMo、BERTのトークン表現、Bi-Encoderによる文埋め込み): トークンのベクトルが周囲の文脈の動的な関数となるような表現を生成します。BERTやELMoでは、「river bank」における「bank」と、「deposit money at the bank」における「bank」には、全く異なる埋め込みベクトルが付与されます。
3. Transformerの隠れ状態: Transformerネットワークの順伝播処理中に、各層で生成される中間ベクトル表現を指します。第0層の入力トークン埋め込みが与えられると、後続の各Transformer層は自己注意機構(Self-Attention)と順伝播型ネットワーク変換を適用し、層 $l$ における隠れ状態ベクトルの系列 $h_l$ を生成します。最終層の隠れ状態は高レベルなコンテキスト埋め込みとして機能しますが、下位層および中間層の隠れ状態は低レベルな構文的、語彙的、構造的特徴を捉えます。したがって、Transformerの隠れ状態は、ネットワーク全体における層ごとの表現の垂直的な連続体全体を網羅しています。
import torch
from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
model = AutoModel.from_pretrained('bert-base-uncased', output_hidden_states=True)
text1 = 'River bank'
text2 = 'Bank deposit'
inputs1 = tokenizer(text1, return_tensors='pt')
inputs2 = tokenizer(text2, return_tensors='pt')
with torch.no_grad():
out1 = model(**inputs1)
out2 = model(**inputs2)
# Layer 0 (Input token embeddings - static lookup before self-attention)
static_bank_1 = out1.hidden_states[0][0, 2] # 'bank'
# Layer 12 (Final contextual hidden state after all attention layers)
contextual_bank_1 = out1.hidden_states[12][0, 2]
contextual_bank_2 = out2.hidden_states[12][0, 1]
print('Cosine similarity of bank in different contexts (Layer 12):',
torch.cosine_similarity(contextual_bank_1, contextual_bank_2, dim=0).item())
AI コーチを使ってこの質問に答えてみる
3 埋め込み空間が何を表しているかを説明し、テキストの埋め込みにおいてコサイン類似度がどのように解釈されるかを述べてください。
埋め込み空間とは、単語、文、文書などの離散的なテキストエンティティがマッピングされる連続的な高次元ベクトル空間 R^d です。この空間では、意味的、統語的、あるいは関係性における類似性が、幾何学的な近接性や方向関係に対応付けられます。この空間内では、距離や角度が意味的な関連性を反映します。
コサイン類似度は2つのベクトル u と v の間の角度 theta のコサインを測定するもので、次のように計算されます。
Cosine Similarity(u, v) = (u . v) / (||u|| ||v||)
テキスト埋め込みにおけるコサイン類似度は、次のように解釈されます。
- 範囲と向き: 通常、[-1, 1](非負の埋め込みの場合は [0, 1])の範囲に収まるスカラー値を出力します。1.0 に近い値は、2つのベクトルがほぼ同じ方向を向いていることを示し、高い意味的類似度やトピックの一致を反映します。0.0 付近の値は直交(意味的な独立性または無関係)を意味し、負の値は反対の向きを示します。
- 大きさへの不変性: ユークリッド距離(L2距離)や内積とは異なり、コサイン類似度はベクトルの長さ(ノルム)を正規化します。テキスト埋め込みにおいて、ベクトルの大きさは系列長、トークンの出現頻度、または用語の専門性の高さと相関することがあります。純粋に方向の一致に焦点を当てることで、コサイン類似度はベクトルの大きさの違いから意味的な方向性を切り離して評価できます。
import numpy as np
def cosine_sim(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# Hypothetical 3D embeddings
v_king = np.array([0.9, 0.1, 0.4])
v_queen = np.array([0.85, 0.15, 0.42])
v_apple = np.array([0.1, 0.9, -0.2])
print('Sim(king, queen):', round(cosine_sim(v_king, v_queen), 4))
print('Sim(king, apple):', round(cosine_sim(v_king, v_apple), 4))
AI コーチを使ってこの質問に答えてみる
4 Transformerの入力におけるトークン埋め込み(Token Embeddings)、位置埋め込み(Positional Embeddings)、セグメント埋め込みまたはタイプ埋め込み(Segment / Type Embeddings)の違いを説明してください。
Transformerの入力(特にBERTスタイルのアーキテクチャ)では、各トークンの入力表現は通常、以下の3つの異なる埋め込みベクトルを要素ごとに加算(element-wise sum)することによって構成されます。
1. トークン埋め込み(Token Embeddings): 語彙内の離散的なトークンIDを、トークンの核となる意味論的・語彙的同一性を表す密ベクトルにマッピングします。
2. 位置埋め込み(Positional Embeddings): 自己注意機構(self-attention)が本質的に順序不変(置換不変)であるという特性を補うため、トークンの順序と並びのインデックスに関する情報を表現に注入します。
3. セグメント(またはトークンタイプ)埋め込み(Segment / Token Type Embeddings): 単一の入力シーケンスにまとめられた異なるテキストスパンや文(ペア分類や質問応答タスクにおける文Aと文Bなど)を区別します。
これらを組み合わせることで、最初のTransformer層に入力される前に、トークンの意味、位置、およびシーケンス内のグループ情報を符号化した単一の密な入力テンソルが提供されます。
import torch
import torch.nn as nn
vocab_size, max_seq_len, num_segments, d_model = 30522, 512, 2, 768
tok_embed = nn.Embedding(vocab_size, d_model)
pos_embed = nn.Embedding(max_seq_len, d_model)
seg_embed = nn.Embedding(num_segments, d_model)
input_ids = torch.tensor([[101, 7592, 102, 2023, 102]]) # Token IDs
type_ids = torch.tensor([[0, 0, 0, 1, 1 ]]) # Segment IDs (Sentence A vs B)
positions = torch.arange(input_ids.size(1)).unsqueeze(0) # Indices: [0, 1, 2, 3, 4]
# Final representation is the element-wise sum
input_rep = tok_embed(input_ids) + pos_embed(positions) + seg_embed(type_ids)
print(input_rep.shape)
AI コーチを使ってこの質問に答えてみる
5 クエリ、キー、バリュー、およびマルチヘッドアテンションを含め、シーケンス内のトークン同士を関連付けるメカニズムとしてのアテンションについて説明してください。
アテンションは、シーケンス内の各トークンが文脈に応じたマッチングに基づいて情報を動的にルーティングし、他のすべてのトークンの関連度を重み付けできるようにするメカニズムです。線形射影により、各トークンの入力は3つのベクトルに変換されます: - クエリ(Query / Q):現在のトークンがどのような情報を求めているかを表します。 - キー(Key / K):クエリとの照合用として、トークンが提供できる属性やコンテンツを表します。 - バリュー(Value / V):集約される実際の情報ペイロードを保持します。 スケールド・ドットプロダクト・アテンションでは、クエリとキーの積($Q K^T$)を計算し、次元数が大きい場合の勾配消失を防ぐために $\frac{1}{\sqrt{d_k}}$ でスケーリングし、softmax関数で正規化することでアテンションスコアを算出します。最終的な出力はバリューの重み付き和となります: $$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$ マルチヘッドアテンション(MHA: Multi-Head Attention)は、$Q$、$K$、$V$ を並列に複数の独立した表現部分空間(ヘッド)へ射影します。これにより、モデルは各位置にわたって異なる種類のリレーション(構文構造、照応関係、長距離の依存関係など)へ同時にアテンションを向けることができます。各ヘッドの出力は連結され、元のモデル次元へと線形射影されます。
import torch
import torch.nn.functional as F
# Q, K, V: [batch_size, seq_len, head_dim]
Q = torch.randn(1, 4, 64)
K = torch.randn(1, 4, 64)
V = torch.randn(1, 4, 64)
d_k = Q.size(-1)
scores = torch.matmul(Q, K.transpose(-2, -1)) / (d_k ** 0.5)
attn_weights = F.softmax(scores, dim=-1)
output = torch.matmul(attn_weights, V)
print("Output shape:", output.shape)
AI コーチを使ってこの質問に答えてみる
6 因果的デコーダ(causal decoder)と双方向エンコーダ(bidirectional encoder)でアテンションマスキングがどのように異なるか、またそれによって可能になる挙動や防止される挙動を説明してください。
アテンションマスキングは、許可されていないトークンのペアに対してアテンションロジット(softmax適用前のスコア)を $-\infty$ に設定することで、どのトークンが他のどのトークンを参照できるかを制御し、softmax適用後のアテンション重みを厳密に0にします。
1. 因果的デコーダ(例: GPT、LLaMA): 下三角行列の因果的(自己回帰)マスクを使用します。位置 $i$ のトークンは $j \le i$ の位置にのみアテンションを向けることができます。これにより未来のトークンへのアテンションが遮断され、推論時の自己回帰的な1トークンずつの生成が可能になり、並列学習時の未来トークンのラベルリークが防止されます。
2. 双方向エンコーダ(例: BERT): 因果的マスクは使用せず、すべてのトークンがシーケンス全体の過去および未来のすべてのトークンを参照できます。バッチ処理されたシーケンス内の無効な `[PAD]` トークンを有効なトークンが参照しないよう、パディングマスクを使用します。双方向アテンションは包括的な文脈表現を生成するため理解タスクには理想的ですが、直接的な1パスの自己回帰テキスト生成は行えません。
import torch
import torch.nn.functional as F
scores = torch.randn(3, 3)
# Create upper-triangular mask for future positions
causal_mask = torch.triu(torch.ones(3, 3, dtype=torch.bool), diagonal=1)
# Mask future positions with -inf before softmax
masked_scores = scores.masked_fill(causal_mask, float('-inf'))
atten_weights = F.softmax(masked_scores, dim=-1)
print(atten_weights)
AI コーチを使ってこの質問に答えてみる
これらの回答を声に出して練習する準備はできていますか?
声で回答し、技術の深さ、構成、英語でのコミュニケーションについてフィードバックを受け取れます。
7 言語タスクにおけるTransformerアーキテクチャのEncoder-Only、Decoder-Only、Encoder-Decoderの違いについて説明してください。
これら3つの主要なTransformerアーキテクチャは、アテンションのマスキングパターンと主な運用目的に根本的な違いがあります。
1. Encoder-Only(例: BERT、RoBERTa): 双方向の自己アテンション(self-attention)を使用し、すべてのトークンが系列内の他のすべてのトークンに同時にアテンションを向けることができます。入力系列全体に対して豊かな文脈表現を生成するため、分類、抽出型QA(質問応答)、特徴量表現の獲得に最適です。自己回帰的なテキスト生成を自然に行うことはできません。
2. Decoder-Only(例: GPT-3、Llama、Mistral): 因果的(一方向)自己アテンションを使用し、トークン $i$ は位置 $j \le i$ のトークンにのみアテンションを向けることができます。次のトークン予測(next-token prediction)を用いて自己回帰的に学習され、生成言語モデル、コード生成、自由対話における標準的なアーキテクチャとして利用されています。
3. Encoder-Decoder(例: T5、BART): 双方向エンコーダと自己回帰型の因果的デコーダを組み合わせた構成です。デコーダは生成されたトークンに対する因果的自己アテンションに加えて、エンコーダの出力表現をクエリするクロスアテンション(cross-attention)層を備えています。このアーキテクチャは、翻訳や要約などのSequence-to-Sequence変換タスク専用に設計されています。
# Causal mask (Decoder-Only) vs Full mask (Encoder-Only)
import torch
seq_len = 4
encoder_mask = torch.ones(seq_len, seq_len) # Full bidirectional attention
decoder_causal_mask = torch.tril(torch.ones(seq_len, seq_len)) # Lower-triangular
print("Encoder Mask:
", encoder_mask)
print("Decoder Causal Mask:
", decoder_causal_mask)
AI コーチを使ってこの質問に答えてみる