NumPyは深層学習初心者にとって必須:PyTorchより先に学ぶべき理由

なぜ深層学習初心者はNumPyから始めるべきか?



深層学習の書籍や講義では、ほとんどの場合 PyTorch、TensorFlow などのフレームワーク が最初に登場します。しかし実際にモデルを作る段階になると、こんな疑問にぶつかりがちです。

  • 「テンソル(tensor)って何?」
  • 「shape が合わないのにエラーが出る?」
  • 「バッチをこう結合すればいいと思っていたのに…?」

このような混乱は、NumPyを十分に理解していない状態で深層学習フレームワークに飛び込むときに起こります。

  • PyTorch の TensorNumPy の ndarray とほぼ同じ概念
  • データ前処理、バッチ作成、統計計算などは依然として NumPy スタイルの思考が必要

したがって「深層学習を本当に学びたい」なら、NumPy は実質的に必須に近い基礎体力だと言えます。


NumPy とは何か?

NumPy(ナムパイ) は “Numerical Python” の略で、Python で高速に数値計算を行うためのライブラリです。

主なキーワードを整理すると:

  • 多次元配列(ndarray):ベクトル、行列、テンソル表現の基本
  • ベクトル化演算for 文なしで大量演算を一度に処理
  • ブロードキャスティング:形状(shape)が異なる配列同士も賢く演算
  • 線形代数演算:行列積、転置、逆行列など
  • 乱数モジュール:データサンプリング、正規分布、ランダム初期化など

深層学習で使うほぼすべての式が 「ベクトルと行列演算」 に帰結するため、これを便利に扱える NumPy は深層学習の言語と言っても過言ではありません。


Python リスト vs NumPy 配列



まず Python の基本リストと NumPy 配列の違いを簡単に比較します。

# Python の基本リスト
a = [1, 2, 3, 4]
b = [10, 20, 30, 40]

# リスト同士の足し算
print(a + b)
# 結果: [1, 2, 3, 4, 10, 20, 30, 40]  (連結)

リストの + は「要素ごとに足し算」ではなく リストの連結です。

import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])

print(a + b)
# 結果: [11 22 33 44]  (要素別加算)

NumPy 配列の + は私たちが数学で期待する 要素別(element-wise)演算です。 深層学習フレームワークの Tensorこの NumPy スタイルをそのまま踏襲します。


ベクトル化:ループを減らし、数式のようにコードを書く

深層学習コードでは for 文を最小化するよう頻繁に言われます。代わりに ベクトル化(vectorization) を使います。

例:すべての要素に二乗を適用します。

Python リスト + for 文

data = [1, 2, 3, 4, 5]
squared = []
for x in data:
    squared.append(x ** 2)

print(squared)  # [1, 4, 9, 16, 25]

NumPy ベクトル化

import numpy as np

data = np.array([1, 2, 3, 4, 5])
squared = data ** 2

print(squared)  # [ 1  4  9 16 25]
  • コードが短く
  • より 数式に近く 読みやすい
  • 内部は C で実装されているため 性能も格段に良い

PyTorch や TensorFlow のテンソル演算も、基本はこの NumPy 的なベクトル化の発想に沿っています。


ブロードキャスティング:形状が違っても一緒に演算する

ブロードキャスティング(broadcasting)は 異なるサイズの配列同士も自動で形状を合わせる規則です。

例:各サンプルに同じ定数値を足す

import numpy as np

x = np.array([[1, 2, 3],
              [4, 5, 6]])   # shape: (2, 3)

b = np.array([10, 20, 30])  # shape: (3,)

y = x + b
print(y)
# [[11 22 33]
#  [14 25 36]]

x は (2, 3) で、b は (3,) ですが、 NumPy は b(1, 3) とみなして各行に適用し、結果として (2, 3) の形で計算します。

PyTorch でも同様です:

import torch

x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])
b = torch.tensor([10, 20, 30])

y = x + b
print(y)

したがって ブロードキャスティング規則を NumPy で確実に理解すれば PyTorch テンソル演算もずっと自然に扱えます。


ベクトル、行列、テンソル:NumPy で深層学習を表現する

深層学習で頻繁に登場する概念を NumPy で見ると:

  • ベクトル(vector):1 次元配列 → shape: (N,)
  • 行列(matrix):2 次元配列 → shape: (M, N)
  • テンソル(tensor):3 次元以上の配列

  • 例:画像バッチ

    • batch_size = 32、白黒 28x28 画像 → shape: (32, 28, 28)

例:簡単な行列積

import numpy as np

# 入力ベクトル(特徴 3 個)
x = np.array([1.0, 2.0, 3.0])           # shape: (3,)

# 重み行列(入力 3 → 出力 2)
W = np.array([[0.1, 0.2, 0.3],
              [0.4, 0.5, 0.6]])        # shape: (2, 3)

# 行列積: y = W @ x
y = W @ x
print(y)  # [1.4 3.2]

このコードは実質的に 単層線形レイヤー(linear layer) を計算するものです。 PyTorch に移すと:

import torch

x = torch.tensor([1.0, 2.0, 3.0])   # shape: (3,)
W = torch.tensor([[0.1, 0.2, 0.3],
                  [0.4, 0.5, 0.6]]) # shape: (2, 3)

y = W @ x
print(y)

形と意味がほぼ同じです。 NumPy 行列演算に慣れること = 深層学習式を読む力を身につけることに他なりません。


NumPy と PyTorch はどう結びつく?

1. Tensor と ndarray は“いとこ”のような関係

  • 両者とも n 次元配列 + ベクトル化演算 を提供
  • shapereshapetransposesummean など関数名と動作が非常に似ている

そのため多くの人は NumPy を「PyTorch テンソルを理解するための練習場」として使います。

2. データ前処理は通常 NumPy スタイル

深層学習プロジェクトで頻繁に行う作業:

  • CSV、画像、ログなど多様なデータを読み込む
  • 数値化する
  • 正規化、標準化、スライシング、シャッフル、バッチ分割など

これらは NumPy + pandas の組み合わせで行うケースが多いです。

import numpy as np
import torch

# NumPy でデータ準備
np_data = np.random.randn(100, 3)  # 100 サンプル、3 特徴

# PyTorch テンソルへ変換
tensor_data = torch.from_numpy(np_data).float()
print(tensor_data.shape)  # torch.Size([100, 3])

逆に PyTorch テンソルを再び NumPy に戻して後処理するケースも多いです。

y = tensor_data.mean(dim=0)  # PyTorch テンソル
y_np = y.detach().cpu().numpy()

つまり、実務では NumPy と PyTorch は常に行き来する関係です。

3. GPU 計算は PyTorch、基礎の理解や検証は NumPy

  • PyTorch テンソルは GPU(CUDA)で動き、自動微分をサポート
  • NumPy は CPU ベースだが、概念を練習・デバッグするにはずっとシンプル

したがって:

  1. アイデアや式をまず NumPy で小さく実験
  2. 検証が済めば PyTorch コードへ移す

という開発手法を取る人も多いです。


深層学習でよく使う NumPy パターン例

1. ランダム初期化 & ノイズ追加

import numpy as np

# 重み初期化(正規分布)
W = np.random.randn(3, 3) * 0.01

# 入力にノイズ追加
x = np.array([1.0, 2.0, 3.0])
noise = np.random.normal(0, 0.1, size=x.shape)
x_noisy = x + noise

2. データ正規化(平均 0、標準偏差 1)

X = np.random.randn(100, 3) * 10 + 50  # ざっくり作ったデータ

mean = X.mean(axis=0)   # 各 feature の平均
std = X.std(axis=0)     # 各 feature の標準偏差

X_norm = (X - mean) / (std + 1e-8)

この正規化は、深層学習では 学習の安定性や性能に影響します。

3. One-hot エンコーディング

num_classes = 4
labels = np.array([0, 2, 1, 3])  # 4 サンプルのクラスインデックス

one_hot = np.eye(num_classes)[labels]
print(one_hot)
# [[1. 0. 0. 0.]
#  [0. 0. 1. 0.]
#  [0. 1. 0. 0.]
#  [0. 0. 0. 1.]]

PyTorch でも同じ方法で one-hot を考え、コードを書きます。

4. バッチ分割

X = np.random.randn(100, 3)  # 100 サンプル
batch_size = 16

for i in range(0, len(X), batch_size):
    batch = X[i:i+batch_size]
    # ここで batch をモデルに入れると考えて OK

このパターンは PyTorch の DataLoader の概念と直接結びつきます。


NumPy を学ぶときに押さえておくべきポイント

深層学習を目指す場合、すべての機能を網羅する必要はありません。以下の項目を中心に習得すれば十分です。

  1. ndarray 基本 * np.arraydtypeshapereshapeastype
  2. インデクシング & スライシング * x[0]x[1:3]x[:, 0]x[:, 1:3] * ブールインデクシング:x[x > 0]
  3. 基本演算 * +-*/**、比較演算 * np.sumnp.meannp.maxnp.minaxis の概念
  4. 線形代数 * 行列積:@ または np.dot * 転置:x.T
  5. ブロードキャスティング * スカラー加算/乗算 * (N, D) + (D,)(N, 1) などのパターン
  6. 乱数関連関数 * np.random.randnnp.random.randintnp.random.permutation
  7. PyTorch 連携 * torch.from_numpytensor.numpy() * shape がどのように連携するか確認

この程度をしっかり身につければ、PyTorch のチュートリアルで出てくるテンソル演算のほとんどがずっと自然に感じられます。


まとめ:NumPy は「深層学習の文法書」

整理すると:

  • NumPy は 数値計算のための多次元配列ライブラリ
  • PyTorch の Tensor は実質的に NumPy ndarray の深層学習版
  • ベクトル化、ブロードキャスティング、線形代数を NumPy で習得すれば
  • テンソル shape エラーを減らせる
  • 論文式をコードに移すのが楽になる
  • データ前処理/分析力も同時に向上

深層学習を「フレームワークの使い方」ではなく 数学的/配列演算の観点から理解したいなら、NumPy は最適な出発点です。

image of a dev researching deep-learning