PyTorchを学び始めたとき、テンソルの形状変換やバックプロパゲーションの仕組みがどうにもイメージしにくかったんですよね。数式だけだとピンとこない。でも、テンソルを「箱」や「立体ブロック」として視覚的に捉えると、一気に理解が進みました。この記事では、PyTorchの基本をビジュアルに解説していきます。
テンソルとは「多次元の数値の箱」
PyTorchの中心にあるのがテンソル(Tensor)です。NumPyのndarrayに似ていますが、GPU上で計算できることと、自動微分の仕組みを持っている点が異なります。
- スカラー: 0次元テンソル(ただの数値、例: 3.14)
- ベクトル: 1次元テンソル(数値の列、例: [1, 2, 3])
- 行列: 2次元テンソル(数値の表、例: 3×4の表)
- 3次元以上: カラー画像(高さ×幅×RGB)やバッチ処理(バッチ数×高さ×幅×チャンネル)
視覚的に捉えると、1次元は線、2次元は面、3次元は立方体、4次元は立方体が並んだ棚、というイメージが分かりやすいかもしれません。
テンソル操作を図で理解する
PyTorchで頻繁に使うテンソル操作には、reshape、squeeze、unsqueeze、transposeなどがあります。これらは「箱の形を変える」操作として捉えると直感的です。
import torch
# 12個の要素を持つ1次元テンソル
x = torch.arange(12) # [0,1,2,...,11]
# 3×4の行列に変形
y = x.reshape(3, 4) # 3行4列
# 2×2×3の立方体に変形
z = x.reshape(2, 2, 3) # 同じ12個の数値、形だけ変わる
# 次元を追加 (unsqueeze)
a = y.unsqueeze(0) # shape: 1×3×4(バッチ次元を追加)
# 次元を削除 (squeeze)
b = a.squeeze(0) # shape: 3×4に戻る
reshapeは「中身はそのまま、箱の形だけ変える」操作です。12個のブロックを1列に並べるか、3行4列に並べるか、2段×2列×3個に積むか。データは同じで、見方だけが変わるんですよね。
自動微分(Autograd)の仕組み
PyTorchの最大の特徴が自動微分です。requires_grad=Trueを指定したテンソルで計算を行うと、PyTorchが内部で計算グラフを構築します。これは「どの計算をどの順番で行ったか」の記録ですね。
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x * 3 # 各要素を3倍
z = y.sum() # 合計
z.backward() # 逆伝播
print(x.grad) # tensor([3., 3.]) — zをxで微分した結果
ビジュアルに考えると、計算グラフは木構造のようなものです。根っこが最終的な損失値で、枝が各演算、葉がパラメータ。backward()を呼ぶと、根から葉に向かって勾配が流れていく。この仕組みのおかげで、複雑なニューラルネットワークでも効率的にパラメータを更新できるわけです。
MicroGPTの可視化ツールのように、内部動作を目で見て理解できると学習効率が格段に上がります。
ニューラルネットワークの構築
PyTorchでニューラルネットワークを作るには、torch.nn.Moduleを継承したクラスを定義します。各層(レイヤー)は「入力テンソルを受け取って、変換して、出力テンソルを返す箱」として考えると分かりやすいです。
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(784, 128) # 784入力 → 128出力
self.relu = nn.ReLU() # 活性化関数
self.layer2 = nn.Linear(128, 10) # 128入力 → 10出力
def forward(self, x):
x = self.layer1(x) # 線形変換
x = self.relu(x) # 非線形変換(負の値を0に)
x = self.layer2(x) # 最終出力
return x
このネットワークを図にすると、784個のノードが128個のノードに全結合し、さらに10個のノードに接続される3層構造になります。PyTorch公式のnnモジュールドキュメントには、もっと多くの層の種類が載っています。
学習ループを理解する
PyTorchの学習ループは、以下の4ステップの繰り返しです。
- 順伝播(Forward): 入力データをネットワークに通して予測を得る
- 損失計算(Loss): 予測と正解の差を数値化する
- 逆伝播(Backward): 損失に対する各パラメータの勾配を計算する
- 更新(Update): 勾配の方向にパラメータを少し動かす
model = SimpleNet()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
for epoch in range(10):
for inputs, labels in dataloader:
optimizer.zero_grad() # 勾配リセット
outputs = model(inputs) # 1. 順伝播
loss = criterion(outputs, labels) # 2. 損失計算
loss.backward() # 3. 逆伝播
optimizer.step() # 4. パラメータ更新
この4ステップを何千回も繰り返すことで、モデルが徐々にデータのパターンを学んでいきます。Qwen3.5のようなマルチモーダルAIも、基本的にはこの学習ループの延長線上にあるわけです。
GPU活用のポイント
PyTorchでGPUを使うのは驚くほど簡単です。テンソルとモデルを.to('cuda')でGPUに送るだけで、計算が自動的にGPU上で実行されます。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = SimpleNet().to(device)
inputs = inputs.to(device)
注意点として、テンソルとモデルが同じデバイス上にないとエラーになります。「CPUのテンソルとGPUのモデルは混ぜられない」ということですね。LLMエージェントのコスト問題でも触れましたが、GPU利用は計算速度と引き換えにコストやリソース管理の課題が出てきます。
まとめ
PyTorchの学習は、テンソルを「形のある箱」として、計算グラフを「木構造」として、ニューラルネットワークを「変換の連鎖」として捉えると、ぐっと理解しやすくなります。数式が苦手でも、視覚的なイメージがあれば十分に入門できるはずです。
まずはPyTorch公式チュートリアルで手を動かしてみることをお勧めします。コードを書きながら、テンソルの形が変わっていく様子をprint(tensor.shape)で確認していくと、感覚が掴めてくると思います。
