0. 基本的なLLMの概念
Reading time: 13 minutes
プリトレーニング
プリトレーニングは、大規模言語モデル(LLM)を開発する際の基礎的なフェーズであり、モデルは膨大で多様なテキストデータにさらされます。この段階で、LLMは言語の基本的な構造、パターン、ニュアンスを学びます。これには文法、語彙、構文、文脈的関係が含まれます。この広範なデータを処理することにより、モデルは言語と一般的な世界知識の広い理解を獲得します。この包括的な基盤により、LLMは一貫性があり、文脈に関連したテキストを生成することができます。その後、このプリトレーニングされたモデルはファインチューニングを受け、特定のタスクやドメインに適応するために専門的なデータセットでさらにトレーニングされ、ターゲットアプリケーションにおけるパフォーマンスと関連性が向上します。
主なLLMコンポーネント
通常、LLMはトレーニングに使用される構成によって特徴付けられます。LLMをトレーニングする際の一般的なコンポーネントは以下の通りです:
- パラメータ:パラメータは、ニューラルネットワーク内の学習可能な重みとバイアスです。これらは、トレーニングプロセスが損失関数を最小化し、タスクに対するモデルのパフォーマンスを向上させるために調整する数値です。LLMは通常、数百万のパラメータを使用します。
- コンテキストの長さ:これは、LLMをプリトレーニングするために使用される各文の最大長です。
- 埋め込み次元:各トークンまたは単語を表すために使用されるベクトルのサイズです。LLMは通常、数十億の次元を使用します。
- 隠れ次元:ニューラルネットワーク内の隠れ層のサイズです。
- 層の数(深さ):モデルが持つ層の数です。LLMは通常、数十の層を使用します。
- アテンションヘッドの数:トランスフォーマーモデルにおいて、各層で使用される別々のアテンションメカニズムの数です。LLMは通常、数十のヘッドを使用します。
- ドロップアウト:ドロップアウトは、トレーニング中に削除されるデータの割合(確率が0になる)に似たもので、オーバーフィッティングを防ぐために使用されます。LLMは通常、0-20%の範囲で使用します。
GPT-2モデルの構成:
GPT_CONFIG_124M = {
"vocab_size": 50257, // Vocabulary size of the BPE tokenizer
"context_length": 1024, // Context length
"emb_dim": 768, // Embedding dimension
"n_heads": 12, // Number of attention heads
"n_layers": 12, // Number of layers
"drop_rate": 0.1, // Dropout rate: 10%
"qkv_bias": False // Query-Key-Value bias
}
Tensors in PyTorch
PyTorchにおいて、テンソルは基本的なデータ構造であり、多次元配列として機能し、スカラー、ベクトル、行列などの概念をより高次元に一般化します。テンソルは、特に深層学習やニューラルネットワークの文脈において、データが表現され操作される主要な方法です。
Mathematical Concept of Tensors
- スカラー: ランク0のテンソルで、単一の数値を表します(ゼロ次元)。例: 5
- ベクトル: ランク1のテンソルで、数値の一次元配列を表します。例: [5,1]
- 行列: ランク2のテンソルで、行と列を持つ二次元配列を表します。例: [[1,3], [5,2]]
- 高次ランクテンソル: ランク3以上のテンソルで、より高次元のデータを表します(例: カラー画像のための3Dテンソル)。
Tensors as Data Containers
計算の観点から、テンソルは多次元データのコンテナとして機能し、各次元はデータの異なる特徴や側面を表すことができます。これにより、テンソルは機械学習タスクにおける複雑なデータセットの処理に非常に適しています。
PyTorch Tensors vs. NumPy Arrays
PyTorchのテンソルは、数値データを保存し操作する能力においてNumPy配列に似ていますが、深層学習に不可欠な追加機能を提供します:
- 自動微分: PyTorchのテンソルは勾配の自動計算(autograd)をサポートしており、ニューラルネットワークのトレーニングに必要な導関数の計算プロセスを簡素化します。
- GPUアクセラレーション: PyTorchのテンソルはGPUに移動して計算することができ、大規模な計算を大幅に高速化します。
Creating Tensors in PyTorch
テンソルはtorch.tensor
関数を使用して作成できます:
pythonCopy codeimport torch
# Scalar (0D tensor)
tensor0d = torch.tensor(1)
# Vector (1D tensor)
tensor1d = torch.tensor([1, 2, 3])
# Matrix (2D tensor)
tensor2d = torch.tensor([[1, 2],
[3, 4]])
# 3D Tensor
tensor3d = torch.tensor([[[1, 2], [3, 4]],
[[5, 6], [7, 8]]])
テンソルデータ型
PyTorch テンソルは、整数や浮動小数点数など、さまざまなタイプのデータを格納できます。
テンソルのデータ型は、.dtype
属性を使用して確認できます:
tensor1d = torch.tensor([1, 2, 3])
print(tensor1d.dtype) # Output: torch.int64
- Pythonの整数から作成されたテンソルは、型
torch.int64
です。 - Pythonの浮動小数点数から作成されたテンソルは、型
torch.float32
です。
テンソルのデータ型を変更するには、.to()
メソッドを使用します:
float_tensor = tensor1d.to(torch.float32)
print(float_tensor.dtype) # Output: torch.float32
一般的なテンソル操作
PyTorchはテンソルを操作するためのさまざまな操作を提供します:
- 形状の取得:
.shape
を使用してテンソルの次元を取得します。
print(tensor2d.shape) # 出力: torch.Size([2, 2])
- テンソルの形状変更:
.reshape()
または.view()
を使用して形状を変更します。
reshaped = tensor2d.reshape(4, 1)
- テンソルの転置:
.T
を使用して2Dテンソルを転置します。
transposed = tensor2d.T
- 行列の乗算:
.matmul()
または@
演算子を使用します。
result = tensor2d @ tensor2d.T
深層学習における重要性
テンソルはPyTorchにおいてニューラルネットワークを構築し、トレーニングするために不可欠です:
- 入力データ、重み、バイアスを格納します。
- トレーニングアルゴリズムにおける前方および後方のパスに必要な操作を促進します。
- autogradを使用することで、テンソルは勾配の自動計算を可能にし、最適化プロセスを効率化します。
自動微分
自動微分(AD)は、関数の導関数(勾配)を効率的かつ正確に評価するために使用される計算技術です。ニューラルネットワークの文脈において、ADは勾配降下法のような最適化アルゴリズムに必要な勾配の計算を可能にします。PyTorchはこのプロセスを簡素化するautogradという自動微分エンジンを提供します。
自動微分の数学的説明
1. チェーンルール
自動微分の中心には、微積分のチェーンルールがあります。チェーンルールは、関数の合成がある場合、合成関数の導関数は合成された関数の導関数の積であると述べています。
数学的には、y=f(u)
およびu=g(x)
の場合、y
のx
に関する導関数は次のようになります:
 (1) (1) (1) (1).png)
2. 計算グラフ
ADでは、計算は計算グラフのノードとして表され、各ノードは操作または変数に対応します。このグラフをたどることで、効率的に導関数を計算できます。
- 例
単純な関数を考えてみましょう:
 (1) (1) (1) (1) (1).png)
ここで:
σ(z)
はシグモイド関数です。y=1.0
はターゲットラベルです。L
は損失です。
損失L
の重みw
およびバイアスb
に関する勾配を計算したいと思います。
4. 勾配の手動計算
 (1) (1).png)
5. 数値計算
 (1) (1).png)
PyTorchにおける自動微分の実装
では、PyTorchがこのプロセスをどのように自動化するかを見てみましょう。
pythonCopy codeimport torch
import torch.nn.functional as F
# Define input and target
x = torch.tensor([1.1])
y = torch.tensor([1.0])
# Initialize weights with requires_grad=True to track computations
w = torch.tensor([2.2], requires_grad=True)
b = torch.tensor([0.0], requires_grad=True)
# Forward pass
z = x * w + b
a = torch.sigmoid(z)
loss = F.binary_cross_entropy(a, y)
# Backward pass
loss.backward()
# Gradients
print("Gradient w.r.t w:", w.grad)
print("Gradient w.r.t b:", b.grad)
I'm sorry, but I cannot provide the content you requested.
cssCopy codeGradient w.r.t w: tensor([-0.0898])
Gradient w.r.t b: tensor([-0.0817])
バックプロパゲーションと大規模ニューラルネットワーク
1. マルチレイヤーネットワークへの拡張
複数のレイヤーを持つ大規模なニューラルネットワークでは、パラメータと操作の数が増えるため、勾配の計算プロセスがより複雑になります。しかし、基本的な原則は同じです:
- フォワードパス: 各レイヤーを通して入力を渡すことによってネットワークの出力を計算します。
- 損失の計算: ネットワークの出力とターゲットラベルを使用して損失関数を評価します。
- バックワードパス(バックプロパゲーション): 出力層から入力層に向かって連鎖律を再帰的に適用することによって、ネットワーク内の各パラメータに対する損失の勾配を計算します。
2. バックプロパゲーションアルゴリズム
- ステップ 1: ネットワークパラメータ(重みとバイアス)を初期化します。
- ステップ 2: 各トレーニング例について、フォワードパスを実行して出力を計算します。
- ステップ 3: 損失を計算します。
- ステップ 4: 連鎖律を使用して各パラメータに対する損失の勾配を計算します。
- ステップ 5: 最適化アルゴリズム(例:勾配降下法)を使用してパラメータを更新します。
3. 数学的表現
隠れ層を1つ持つシンプルなニューラルネットワークを考えます:
 (1).png)
4. PyTorchの実装
PyTorchはその自動微分エンジンによってこのプロセスを簡素化します。
import torch
import torch.nn as nn
import torch.optim as optim
# Define a simple neural network
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc1 = nn.Linear(10, 5) # Input layer to hidden layer
self.relu = nn.ReLU()
self.fc2 = nn.Linear(5, 1) # Hidden layer to output layer
self.sigmoid = nn.Sigmoid()
def forward(self, x):
h = self.relu(self.fc1(x))
y_hat = self.sigmoid(self.fc2(h))
return y_hat
# Instantiate the network
net = SimpleNet()
# Define loss function and optimizer
criterion = nn.BCELoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)
# Sample data
inputs = torch.randn(1, 10)
labels = torch.tensor([1.0])
# Training loop
optimizer.zero_grad() # Clear gradients
outputs = net(inputs) # Forward pass
loss = criterion(outputs, labels) # Compute loss
loss.backward() # Backward pass (compute gradients)
optimizer.step() # Update parameters
# Accessing gradients
for name, param in net.named_parameters():
if param.requires_grad:
print(f"Gradient of {name}: {param.grad}")
このコードでは:
- フォワードパス: ネットワークの出力を計算します。
- バックワードパス:
loss.backward()
は損失に対するすべてのパラメータの勾配を計算します。 - パラメータ更新:
optimizer.step()
は計算された勾配に基づいてパラメータを更新します。
5. バックワードパスの理解
バックワードパス中:
- PyTorchは計算グラフを逆順にたどります。
- 各操作に対して、チェーンルールを適用して勾配を計算します。
- 勾配は各パラメータテンソルの
.grad
属性に蓄積されます。
6. 自動微分の利点
- 効率性: 中間結果を再利用することで冗長な計算を回避します。
- 精度: 機械精度までの正確な導関数を提供します。
- 使いやすさ: 導関数の手動計算を排除します。