ジュリア、Python(NumPy、PyTorch)の配列の次元の違い
概要
JuliaとNumPy、PyTorch(以降、便宜上Pythonと呼ぶ)の高次元配列を扱う際、各次元が意味するものが異なるため注意が必要だ。この違いはJuliaの配列が列優先であり、Pythonの配列が行優先であるために生じる。ちなみに同じ列優先のMatlabはJuliaとの違いがないため、Matlabに慣れているユーザーは特に注意する必要はないが、Pythonに慣れている人はインデックスの間違いに注意しよう。
- 配列の次元とベクトルの次元を混同して使っているので、しっかり理解しよう。
説明
1次元配列
Juliaでは、サイズが$n$の配列は$n$次元の列ベクトルを意味する。
julia> ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0
Pythonでは、サイズが$n$の配列は$n$次元の行ベクトルを意味する。
>>> import numpy as np
>>> np.ones(3)
array([1., 1., 1.])
列か行かの違いはあるが、1次元配列であるため、インデックスに特に注意する点はない。
2次元配列
表面上は2次元までは違いがないように見える。しかし、その意味は異なるので注意が必要だ。まず、Juliaでは配列の次元が後方に伸びる。つまり$(m,n)$配列とは、サイズが$m$の1次元配列(列ベクトル)が$n$個あることを意味する。具体的には$(3,2)$配列は、3次元の列ベクトルが2個あるということだ。
julia> ones(3,2)
3×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
また、Juliaは「列優先」なので、成分のインデックスは上から下へ先に、そして左から右に大きくなる。
julia> A = reshape(range(1,6), (3,2))
3×2 reshape(::UnitRange{Int64}, 3, 2) with eltype Int64:
1 4
2 5
3 6
julia> for i ∈ 1:6
println(A[i])
end
1
2
3
4
5
6
一方、Pythonの配列では新しい次元が前方へ伸びる。つまり$(m,n)$配列とは、サイズが$n$の1次元配列(行ベクトル)が$m$個あるということだ。以下の結果からは、配列が行単位で区分されているのがわかる。
>>> np.ones([3,2])
array([[1., 1.],
[1., 1.],
[1., 1.]])
つまり、見た目だけでは、JuliaとPythonの$(m,n)$配列はどちらも$m \times n$の行列だが、列優先/行優先の違いのためにインデックスの順序が異なる。インデックスの方向はJuliaでは上下左右、Pythonでは左右上下だ。
# julia에서 2차원 배열의 인덱싱은 위에서 아래로, 그 다음 좌에서 우로
julia> A = reshape(range(1,6), (3,2))
3×2 reshape(::UnitRange{Int64}, 3, 2) with eltype Int64:
1 4
2 5
3 6
# python에서 2차원 배열의 인덱싱은 좌에서 우로, 그 다음 위에서 아래로
>>> np.arange(6).reshape(3,2)
array([[0, 1],
[2, 3],
[4, 5]])
3次元配列
Juliaでは、配列の新しい次元が後ろに追加されると言った。従って、$(m,n,k)$配列は、$(m,n)$配列が$k$個あることを意味する。
julia> ones(3,2,4)
3×2×4 Array{Float64, 3}:
[:, :, 1] =
1.0 1.0
1.0 1.0
1.0 1.0
[:, :, 2] =
1.0 1.0
1.0 1.0
1.0 1.0
[:, :, 3] =
1.0 1.0
1.0 1.0
1.0 1.0
[:, :, 4] =
1.0 1.0
1.0 1.0
1.0 1.0
一方、Pythonでは$(m,n,k)$配列は、$(n,k)$配列が$m$個あるということだ。
>>> np.ones([3,2,4])
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
機械学習で
画像データで、$H=\text{hieht}$が高さ、$W=\text{width}$が幅、$C=\text{channel}$がチャンネル数、$B=\text{batch size}$がバッチサイズとした場合、PyTorchでは$(B,C,H,W)$配列であり、Juliaでは$(H,W,C,B)$である。
環境
- OS: Windows11
- バージョン: Julia 1.7.1, Python 3.9.2, numpy 1.19.5