テンソルの次元とは?階数・ランク・shapeの違いをわかりやすく解説

機械学習やディープラーニングを学び始めると、必ず出会う概念が「テンソル」です。
そして、テンソルについて調べると「次元」「階数」「ランク」「shape」など、さまざまな用語が登場し、混乱してしまう方も多いのではないでしょうか。

この記事では、テンソルの次元に関する概念を、初心者にもわかりやすく丁寧に解説します。
具体例を豊富に使いながら、混同しやすい用語の違いも明確にしていきます。

スポンサーリンク

テンソルとは

まず、テンソルの基本から確認しましょう。

テンソル(Tensor)の定義:

テンソルとは、数値を多次元的に配列したデータ構造です。
スカラー、ベクトル、行列を一般化した概念で、機械学習やディープラーニングにおけるデータの基本単位となっています。

身近な例え:

テンソルは、ゲームキャラクターのステータスのようなものです。
1人のキャラクター(1つの情報)を表すのに、「力」「素早さ」「体力」「知力」など、複数の数値パラメータを使います。
このように、1つの対象を複数の数値で表現するのがテンソルです。

重要なポイント:

ニューラルネットワークは文字、画像、音声をそのままでは理解できません。
すべてのデータを数値に変換し、テンソルとして表現する必要があります。

テンソルの基本構造

テンソルを理解するには、以下の3つの概念を押さえることが重要です。

1. スカラー(0階テンソル)

スカラーは、単一の数値です。

例:

42
3.14
-7

特徴:

  • 階数(ランク):0
  • 軸(axis)の数:0
  • shape:()(空のタプル)
  • 次元:0次元

実生活の例:

  • 気温:25度
  • 体重:65kg
  • 年齢:30歳

2. ベクトル(1階テンソル)

ベクトルは、数値を1列に並べたものです。

例:

[1, 2, 3, 4, 5]

特徴:

  • 階数(ランク):1
  • 軸の数:1
  • shape:(5,)
  • 次元:1次元配列

実生活の例:

  • 5科目のテスト点数:[80, 75, 90, 85, 88]
  • 5日間の気温:[22, 24, 23, 25, 26]

3. 行列(2階テンソル)

行列は、数値を縦横(2次元)に並べたものです。

例:

[[1, 2, 3],
 [4, 5, 6]]

特徴:

  • 階数(ランク):2
  • 軸の数:2(行方向と列方向)
  • shape:(2, 3)(2行3列)
  • 次元:2次元配列

実生活の例:

  • 3人の生徒の3科目の成績
  • カレンダー(週×日)
  • モノクロ画像(縦ピクセル×横ピクセル)

4. 3階以上のテンソル

3次元以上のデータ構造です。

3階テンソルの例:

[[[1, 2],
  [3, 4]],
 [[5, 6],
  [7, 8]]]

特徴:

  • 階数(ランク):3
  • 軸の数:3
  • shape:(2, 2, 2)
  • 次元:3次元配列

実生活の例:

  • カラー画像:(縦ピクセル×横ピクセル×RGB色チャンネル)
  • 複数の行列を重ねたもの

重要な用語の違い

テンソルに関する用語は混乱しやすいため、ここで整理します。

階数(ランク / Rank)

定義:

テンソルが持つ軸(axis)の数のことです。
または、テンソルの要素を特定するために必要なインデックスの数とも言えます。

重要な注意:

機械学習における「テンソルのランク」と、線形代数における「行列のランク」は別の概念です。
混同しないように注意してください。

具体例:

  • スカラー:ランク0(インデックス不要)
  • ベクトル:ランク1(1つのインデックスで要素を指定)
  • 行列:ランク2(2つのインデックスで要素を指定)
  • 3階テンソル:ランク3(3つのインデックスで要素を指定)

プログラミングでの確認:

import numpy as np

scalar = 42
vector = np.array([1, 2, 3])
matrix = np.array([[1, 2], [3, 4]])
tensor3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

print(f"スカラーのランク: {np.ndim(scalar)}")  # 0
print(f"ベクトルのランク: {vector.ndim}")      # 1
print(f"行列のランク: {matrix.ndim}")          # 2
print(f"3階テンソルのランク: {tensor3.ndim}")  # 3

オーダー(Order / Degree)

定義:

「階数」や「ランク」と同じ意味で使われることが多い用語です。
テンソルが何次元の配列であるかを示します。

使用例:

  • “This is a 3rd-order tensor”(これは3階のテンソルです)
  • 「2次のテンソル」=「2階のテンソル」=「行列」

次元(Dimension)

「次元」という言葉は、文脈によって2つの異なる意味で使われます。

意味1:階数と同じ意味

「このテンソルは3次元です」と言う場合、「このテンソルは3階です(ランク3です)」という意味です。

意味2:各軸の長さ

「この軸の次元は5です」と言う場合、「この軸の要素数は5です」という意味です。

例:

shape が (3, 4, 5) のテンソルの場合:

  • 階数(ランク):3(3次元配列)
  • 第0軸の次元(長さ):3
  • 第1軸の次元(長さ):4
  • 第2軸の次元(長さ):5

この曖昧さが混乱の原因になるため、正確には以下のように区別します。

軸(Axis / Axes)

定義:

テンソルの各方向を「軸」と呼びます。
ランク2のテンソルには2つの軸があり、ランク3のテンソルには3つの軸があります。

軸の番号付け:

通常、軸には0から始まる番号が振られます。

  • 第0軸(axis 0):最も外側の次元
  • 第1軸(axis 1):2番目の次元
  • 第2軸(axis 2):3番目の次元

例:

shape が (3, 4, 5) のテンソルの場合:

  • 第0軸の長さ:3
  • 第1軸の長さ:4
  • 第2軸の長さ:5

Shape(形状)

定義:

各軸の長さを順番に並べたタプル(組)です。
shapeを見れば、テンソルの構造が完全にわかります。

shapeに含まれる情報:

  1. タプルの長さ = テンソルの階数(ランク)
  2. 各要素の値 = 各軸の長さ

具体例:

import numpy as np

# shape (5,)
vector = np.array([1, 2, 3, 4, 5])
print(f"ベクトルのshape: {vector.shape}")  # (5,)
print(f"階数: {len(vector.shape)}")         # 1

# shape (2, 3)
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
print(f"行列のshape: {matrix.shape}")      # (2, 3)
print(f"階数: {len(matrix.shape)}")        # 2

# shape (2, 3, 4)
tensor3 = np.zeros((2, 3, 4))
print(f"3階テンソルのshape: {tensor3.shape}")  # (2, 3, 4)
print(f"階数: {len(tensor3.shape)}")           # 3

shapeの読み方:

  • (5,):1軸、長さ5
  • (2, 3):2軸、第0軸の長さ2、第1軸の長さ3
  • (2, 3, 4):3軸、第0軸の長さ2、第1軸の長さ3、第2軸の長さ4
  • (4, 28, 28, 3):4軸、バッチサイズ4、高さ28、幅28、色チャンネル3

機械学習における具体例

実際の機械学習では、テンソルはどのように使われているのでしょうか。

画像データ

モノクロ画像(2階テンソル):

shape: (28, 28)
  • 28×28ピクセルのモノクロ画像
  • 各ピクセルの明るさを0〜255の数値で表現
  • 例:MNIST手書き数字データセット

カラー画像(3階テンソル):

shape: (224, 224, 3)
  • 224×224ピクセルのカラー画像
  • 第0軸:高さ(縦方向のピクセル数)
  • 第1軸:幅(横方向のピクセル数)
  • 第2軸:色チャンネル(R, G, Bの3つ)
  • 例:ImageNetデータセット

バッチ処理のカラー画像(4階テンソル):

shape: (32, 224, 224, 3)
  • 32枚の画像をまとめて処理
  • 第0軸:バッチサイズ(画像の枚数)
  • 第1軸:高さ
  • 第2軸:幅
  • 第3軸:色チャンネル

ディープラーニングでは、複数の画像を同時に処理する(バッチ処理)ことで、効率的な学習が可能になります。

時系列データ

1つの時系列データ(2階テンソル):

shape: (100, 5)
  • 100時点のデータ
  • 各時点で5つの特徴量
  • 例:株価データ(始値、終値、高値、安値、出来高)

バッチ処理の時系列データ(3階テンソル):

shape: (64, 100, 5)
  • 64個の時系列データをまとめて処理
  • 第0軸:バッチサイズ
  • 第1軸:時間ステップ数
  • 第2軸:特徴量の数

自然言語処理(NLP)

単語の埋め込みベクトル(2階テンソル):

shape: (10000, 300)
  • 10,000単語の語彙
  • 各単語を300次元のベクトルで表現
  • 例:Word2Vec、GloVe

文章のバッチ(3階テンソル):

shape: (32, 50, 300)
  • 32個の文章をまとめて処理
  • 各文章は最大50単語
  • 各単語は300次元ベクトル

動画データ

動画データ(5階テンソル):

shape: (16, 30, 224, 224, 3)
  • 第0軸:バッチサイズ(動画の本数):16
  • 第1軸:フレーム数(時間):30フレーム
  • 第2軸:高さ:224ピクセル
  • 第3軸:幅:224ピクセル
  • 第4軸:色チャンネル:3(RGB)

PyTorch / TensorFlow / NumPyでの扱い方

各フレームワークでテンソルの情報を取得する方法を見てみましょう。

NumPy

import numpy as np

# 3階テンソルを作成
tensor = np.array([
    [[1, 2, 3], [4, 5, 6]],
    [[7, 8, 9], [10, 11, 12]]
])

print(f"Shape: {tensor.shape}")      # (2, 2, 3)
print(f"階数(ndim): {tensor.ndim}")  # 3
print(f"要素数: {tensor.size}")       # 12
print(f"データ型: {tensor.dtype}")    # int64

PyTorch

import torch

# 3階テンソルを作成
tensor = torch.tensor([
    [[1, 2, 3], [4, 5, 6]],
    [[7, 8, 9], [10, 11, 12]]
])

print(f"Shape: {tensor.shape}")     # torch.Size([2, 2, 3])
print(f"Size: {tensor.size()}")     # torch.Size([2, 2, 3])
print(f"階数(ndim): {tensor.ndim}")  # 3
print(f"要素数: {tensor.numel()}")   # 12
print(f"データ型: {tensor.dtype}")  # torch.int64

注意:

PyTorchでは、shapesize()は同じ結果を返します。

TensorFlow

import tensorflow as tf

# 3階テンソルを作成
tensor = tf.constant([
    [[1, 2, 3], [4, 5, 6]],
    [[7, 8, 9], [10, 11, 12]]
])

print(f"Shape: {tensor.shape}")            # (2, 2, 3)
print(f"階数: {tf.rank(tensor).numpy()}")   # 3
print(f"Shape(関数版): {tf.shape(tensor).numpy()}")  # [2 2 3]
print(f"データ型: {tensor.dtype}")          # int32

注意:

TensorFlowでは、tensor.shapeは属性で、tf.shape(tensor)は関数です。
グラフモードで動的なshapeを扱う場合は、関数版を使用する必要があります。

テンソルの変形(Reshaping)

機械学習では、テンソルの形状を変更する操作が頻繁に行われます。

Reshapeの基本

例1:ベクトルから行列へ

import numpy as np

# shape (6,)
vector = np.array([1, 2, 3, 4, 5, 6])
print(f"元のshape: {vector.shape}")  # (6,)

# shape (2, 3) に変形
matrix = vector.reshape(2, 3)
print(f"変形後のshape: {matrix.shape}")  # (2, 3)
print(matrix)
# [[1 2 3]
#  [4 5 6]]

例2:行列から3階テンソルへ

# shape (6, 4)
matrix = np.arange(24).reshape(6, 4)
print(f"元のshape: {matrix.shape}")  # (6, 4)

# shape (2, 3, 4) に変形
tensor3 = matrix.reshape(2, 3, 4)
print(f"変形後のshape: {tensor3.shape}")  # (2, 3, 4)

Reshapeの制約

重要なルール:

reshapeする前後で、要素の総数は変わりません。

# 元のshape: (6,) → 要素数: 6
# 変形後のshape: (2, 3) → 要素数: 2 × 3 = 6  ✓ OK

# 元のshape: (6,) → 要素数: 6
# 変形後のshape: (2, 4) → 要素数: 2 × 4 = 8  ✗ エラー

-1を使った自動計算

reshapeで-1を指定すると、その軸のサイズを自動計算してくれます。

import numpy as np

# 24個の要素を持つ配列
array = np.arange(24)

# (4, 6) に変形(4 × 6 = 24)
reshaped1 = array.reshape(4, 6)
print(reshaped1.shape)  # (4, 6)

# (-1, 6) に変形(自動的に4と計算される)
reshaped2 = array.reshape(-1, 6)
print(reshaped2.shape)  # (4, 6)

# (2, 3, -1) に変形(自動的に4と計算される)
reshaped3 = array.reshape(2, 3, -1)
print(reshaped3.shape)  # (2, 3, 4)

よくある混乱ポイント

混乱1:「次元」の意味

問題:

「次元」という言葉が2つの意味で使われる。

解決策:

  • テンソル全体の次元数 → 「階数」「ランク」を使う
  • 各軸の長さ → 「軸の長さ」「shape」を使う

例:

tensor = np.zeros((3, 4, 5))
  • ✗「このテンソルは3次元です」(曖昧)
  • ✓「このテンソルの階数は3です」
  • ✓「このテンソルはランク3です」
  • ✓「このテンソルのshapeは(3, 4, 5)です」

混乱2:テンソルのランクと行列のランク

問題:

線形代数の「行列のランク」と「テンソルのランク」は別の概念。

テンソルのランク:

軸の数のこと。

matrix = np.array([[1, 2], [3, 4]])
print(matrix.ndim)  # 2(2階テンソル)

行列のランク(線形代数):

線形独立な行(または列)の数のこと。

matrix = np.array([[1, 2], [3, 4]])
rank = np.linalg.matrix_rank(matrix)
print(rank)  # 2(フルランク)

混乱3:PyTorchとTensorFlowの軸の順序

問題:

画像データの軸の順序がフレームワークによって異なる。

PyTorch:

shape: (バッチ, チャンネル, 高さ, 幅)
例: (32, 3, 224, 224)

TensorFlow / Keras:

shape: (バッチ, 高さ, 幅, チャンネル)
例: (32, 224, 224, 3)

解決策:

フレームワークを切り替える際は、軸の順序を変換する必要があります。

# PyTorchからTensorFlowへの変換
# (バッチ, チャンネル, 高さ, 幅) → (バッチ, 高さ, 幅, チャンネル)
import numpy as np

pytorch_tensor = np.random.rand(32, 3, 224, 224)
tensorflow_tensor = np.transpose(pytorch_tensor, (0, 2, 3, 1))

print(f"PyTorch shape: {pytorch_tensor.shape}")      # (32, 3, 224, 224)
print(f"TensorFlow shape: {tensorflow_tensor.shape}")  # (32, 224, 224, 3)

混乱4:shapeとsizeの違い

NumPy:

  • shape:各軸の長さを表すタプル
  • size:要素の総数
array = np.zeros((3, 4, 5))
print(array.shape)  # (3, 4, 5)
print(array.size)   # 60(3 × 4 × 5)

PyTorch:

  • shape:各軸の長さを表すタプル
  • size():shapeと同じ(メソッド)
  • numel():要素の総数
tensor = torch.zeros(3, 4, 5)
print(tensor.shape)   # torch.Size([3, 4, 5])
print(tensor.size())  # torch.Size([3, 4, 5])
print(tensor.numel()) # 60

テンソルの次元を意識する重要性

なぜテンソルの次元(階数やshape)を正確に理解する必要があるのでしょうか。

理由1:エラーの回避

機械学習では、shapeの不一致が最も多いエラーの原因です。

例:

# モデルは (バッチ, 224, 224, 3) を期待
# 入力が (224, 224, 3) だとエラー

# 解決策:バッチ次元を追加
input_image = np.expand_dims(input_image, axis=0)
# shape: (224, 224, 3) → (1, 224, 224, 3)

理由2:正しいデータ前処理

データの前処理では、適切なshapeに変換する必要があります。

例:画像の正規化

# 間違い:全体の平均・標準偏差で正規化
mean = images.mean()
std = images.std()
normalized = (images - mean) / std

# 正しい:各色チャンネルごとに正規化
# shape: (バッチ, 高さ, 幅, チャンネル)
mean = images.mean(axis=(0, 1, 2), keepdims=True)
std = images.std(axis=(0, 1, 2), keepdims=True)
normalized = (images - mean) / std

理由3:モデル設計の理解

ニューラルネットワークの各層で、テンソルがどのように変換されるかを理解するために、shapeの追跡が不可欠です。

例:畳み込みニューラルネットワーク(CNN)

入力: (32, 224, 224, 3)    # 32枚の224×224カラー画像
↓ Conv2D(64フィルタ)
→ (32, 224, 224, 64)      # 64チャンネルの特徴マップ
↓ MaxPooling2D(2×2)
→ (32, 112, 112, 64)      # サイズが半分に
↓ Flatten
→ (32, 802816)            # 1次元に展開(112×112×64)
↓ Dense(10)
→ (32, 10)                # 10クラスの分類

まとめ

テンソルの次元に関する重要なポイントをまとめます。

テンソルの階数(ランク):

  • 軸(axis)の数のこと
  • 要素を特定するために必要なインデックスの数
  • スカラー:0、ベクトル:1、行列:2、3階以上:3以上

shape(形状):

  • 各軸の長さを並べたタプル
  • shapeを見れば、テンソルの構造が完全にわかる
  • 例:(3, 4, 5)は、3×4×5の3階テンソル

次元(Dimension):

  • 文脈によって2つの意味がある
  • テンソル全体の階数を指す場合
  • 各軸の長さを指す場合

軸(Axis):

  • テンソルの各方向のこと
  • 通常0から番号が振られる
  • 例:shape (3, 4, 5) の場合、第0軸は長さ3、第1軸は長さ4、第2軸は長さ5

機械学習での重要性:

  1. エラーの回避:shapeの不一致が最多エラー原因
  2. データ前処理:適切なshapeへの変換が必要
  3. モデル設計:各層でのshape変化の理解が不可欠

フレームワークごとの違い:

  • NumPy:shapendimsize
  • PyTorch:shapesize()ndimnumel()
  • TensorFlow:shapetf.rank()tf.shape()

注意すべき混乱ポイント:

  1. 「次元」の多義性 → 「階数」「ランク」を使う
  2. テンソルのランクと行列のランク(線形代数)は別物
  3. PyTorchとTensorFlowの軸の順序の違い
  4. shapeとsizeの違い

実践的なアドバイス:

  • コードを書く際は、常にshapeを確認する習慣をつける
  • エラーが出たら、まずshapeの不一致を疑う
  • reshapeする際は、要素の総数が変わらないか確認
  • -1を使った自動計算を活用する

テンソルの次元(階数、shape)を正確に理解することで、機械学習やディープラーニングのコードがぐっと読みやすくなり、エラーも減ります。
最初は複雑に感じるかもしれませんが、具体例で練習を重ねることで、自然に身につきます。

参考情報

この記事は、以下の公式ドキュメントおよび信頼できる技術情報を参考にしています。

※この記事は2025年2月時点の情報に基づいています。

コメント

タイトルとURLをコピーしました