LESSON

PyTorch基礎

田中VPoE:「Step 1 では NumPy でニューラルネットワークをスクラッチ実装したね。実務では、自動微分や GPU 対応を備えた深層学習フレームワークを使う。今回は PyTorch を学ぼう。」

あなた:「TensorFlow もありますが、PyTorch を選ぶ理由は?」

田中VPoE:「PyTorch は Python ライクな書き方ができて直感的だし、研究コミュニティでのシェアが非常に高い。Hugging Face のモデルもほぼ PyTorch ベースだ。実務と研究の両方で使える。」

Tensor の基本操作

PyTorch の中心的なデータ構造は Tensor です。NumPy の ndarray に似ていますが、GPU 上での計算と自動微分に対応しています。

Tensor の作成

import torch
import numpy as np

# 基本的な作成方法
t1 = torch.tensor([1, 2, 3])                    # リストから
t2 = torch.zeros(3, 4)                           # ゼロ行列
t3 = torch.ones(2, 3)                            # 1行列
t4 = torch.randn(3, 3)                           # 標準正規分布
t5 = torch.arange(0, 10, 2)                      # 等差数列

# NumPy からの変換
np_array = np.array([1.0, 2.0, 3.0])
t6 = torch.from_numpy(np_array)                  # NumPy → Tensor
np_back = t6.numpy()                             # Tensor → NumPy

# データ型の指定
t7 = torch.tensor([1, 2, 3], dtype=torch.float32)

print(f"形状: {t4.shape}")
print(f"データ型: {t4.dtype}")
print(f"デバイス: {t4.device}")

Tensor の演算

a = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
b = torch.tensor([[5.0, 6.0], [7.0, 8.0]])

# 要素ごとの演算
print(a + b)         # 加算
print(a * b)         # 要素積
print(a ** 2)        # べき乗

# 行列演算
print(a @ b)         # 行列積
print(torch.matmul(a, b))  # 同上

# リダクション
print(a.sum())       # 全要素の和
print(a.mean(dim=0)) # 列方向の平均
print(a.max(dim=1))  # 行方向の最大値

# 形状変換
c = torch.randn(2, 3, 4)
print(c.reshape(6, 4).shape)   # (6, 4)
print(c.view(2, 12).shape)     # (2, 12)
print(c.permute(2, 0, 1).shape) # (4, 2, 3)

GPU 活用

PyTorch では .to(device) でデータやモデルを GPU に転送できます。

# GPU が利用可能か確認
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用デバイス: {device}")

# Tensor を GPU に転送
x = torch.randn(1000, 1000)
x_gpu = x.to(device)

# GPU 上で計算
y_gpu = x_gpu @ x_gpu.T  # GPU 上で行列積

# CPU に戻す
y_cpu = y_gpu.cpu()
操作CPUGPU
小規模行列積高速オーバーヘッドが大きい
大規模行列積遅い非常に高速
データ転送-CPU⇔GPU転送にコストあり

自動微分(autograd)

PyTorch の最大の特徴の1つが自動微分です。requires_grad=True を設定した Tensor の演算は自動的に計算グラフに記録され、.backward() で勾配が計算されます。

# 自動微分の基本
x = torch.tensor(3.0, requires_grad=True)
y = x ** 2 + 2 * x + 1  # y = x^2 + 2x + 1

y.backward()  # dy/dx を計算
print(f"x = {x.item()}")
print(f"y = {y.item()}")
print(f"dy/dx = {x.grad.item()}")  # dy/dx = 2x + 2 = 8

ニューラルネットワークでの自動微分

# 2層ネットワークの勾配計算
torch.manual_seed(42)

# 入力とラベル
X = torch.randn(4, 2)
y = torch.tensor([0, 1, 1, 0], dtype=torch.float32).unsqueeze(1)

# パラメータ(勾配追跡を有効化)
W1 = torch.randn(2, 4, requires_grad=True)
b1 = torch.zeros(1, 4, requires_grad=True)
W2 = torch.randn(4, 1, requires_grad=True)
b2 = torch.zeros(1, 1, requires_grad=True)

# 順伝播
z1 = X @ W1 + b1
a1 = torch.relu(z1)
z2 = a1 @ W2 + b2
a2 = torch.sigmoid(z2)

# 損失計算
loss = -torch.mean(y * torch.log(a2 + 1e-7) + (1 - y) * torch.log(1 - a2 + 1e-7))

# 逆伝播(全パラメータの勾配が自動計算される)
loss.backward()

print(f"損失: {loss.item():.4f}")
print(f"W1 の勾配: {W1.grad.shape}")  # NumPy で手動計算した dW1 に相当
print(f"W2 の勾配: {W2.grad.shape}")

勾配の管理

# 勾配のリセット(学習ループでは毎回必要)
W1.grad.zero_()

# 勾配計算を無効化(推論時)
with torch.no_grad():
    predictions = torch.sigmoid(X @ W1 + b1)

# 勾配追跡からの切り離し
detached = a2.detach()  # 計算グラフから切り離す

NumPy vs PyTorch 対応表

操作NumPyPyTorch
配列作成np.array()torch.tensor()
ゼロ行列np.zeros()torch.zeros()
乱数np.random.randn()torch.randn()
形状変換.reshape().reshape() / .view()
行列積a @ ba @ b
最大値np.max()torch.max()
GPU 対応不可.to('cuda')
自動微分不可.backward()

まとめ

  • PyTorch の Tensor は NumPy の ndarray に類似し、GPU 計算と自動微分に対応
  • .to(device) で CPU/GPU 間のデータ転送が可能
  • requires_grad=True.backward() で勾配が自動計算される
  • 推論時は torch.no_grad() で不要な勾配計算を省く

チェックリスト

  • Tensor の作成と基本演算ができる
  • NumPy と Tensor の相互変換ができる
  • GPU へのデータ転送の方法を理解した
  • autograd による自動微分の仕組みを理解した

推定読了時間: 30分