![見出し画像](https://assets.st-note.com/production/uploads/images/101321839/rectangle_large_type_2_efd2f913366e117b366b0d33b463597e.png?width=1200)
PyTorch深層学習②テンソル
前回はディープラーニングを学ぶための前提条件について解説しました。また、PyTorchを自分のコンピュータにインストールする手順の話をしました。
今回は、ディープラーニングを学ぶ上で避けて通れないデータ形式であるテンソルについて解説します。
本シリーズの記事リスト
②テンソル
低次元から始めて、テンソルの具体例をいくつか見ていきましょう。
低次元のテンソル
以下は、行列(マトリックス、Matrix)になります。
$$
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}
$$
もっと細かくいうと、2行3列の行列です。行(Row)と列(Column)が縦なのか横なのかで迷ったら小学校の時に列に並んで校長先生の話を聞いたことを思い出してください。縦に並ぶのが列です。あるいはエクセルの行(Row)と列(Column)で考えても良いかもしれません。
行列には行と列があるのですが、このことを行列は2次元であるとも言います。また、2つの軸があるとも言えます。いろんな言い方がありますが全部よく出てくるので慣れてください。
Pythonなどでプログラミングをする際には行と列の位置は0から始まるインデックス指定します。よって、行0列1の値は2となります。
また、行列はテンソルでもあります。行と列の2つの軸があるので2次元テンソルと言います。この2次元テンソルを$${M}$$と呼びましょう。
$$
M = \begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6
\end{bmatrix}
$$
この$${M}$$を使って行0列1の値を以下のように指定します。
$$
M[0, 1] \rightarrow \ 2
$$
同様に考えると$${M[1, 2]}$$は$${6}$$になります。
では、$${M[0]}$$は何でしょうか。
この場合は最初の次元のインデックスしか指定していないので、それ以降の次元の値をすべて返すことになります。
$$
M[0] \rightarrow [1, 2, 3]
$$
つまり、$${M[0]}$$は行0の値をすべて返します。返された値は数字の並びなのでべクトルと呼びます。数字の区切りが分かりやすいようにカンマをつけています。つけない表記の仕方もあります。その際は空白を十分に取っておけば間違いがないでしょう。
なお、ベクトルは1次元なので1次元のテンソルとも呼べます。
おそらくパターンが見えてきたと思いますが、行列は2次元のテンソルでベクトルは1次元のテンソルです。つまり、テンソルは次元の異なる数値の並びの総称であり、行列やベクトルを知っているならすでにテンソルも知っていることになります。
では$${M[0, 1]}$$で返される値は何次元のテンソルでしょうか。$${M[0, 1]}$$は数値の2を返します。普通の数字はスカラーと呼びますが次元がないので0次元のテンソルと呼びます。
このようにテンソルではさまざまな次元の数値の集まりを同じ枠組みで捉えることができるようになっています。異なるのは次元のみですべてはテンソルになります。
しかし、実際には行列、ベクトル、数値(スカラー)といった名前の方がよく使われます。特に高校数学などでは3次元以上のテンソルを扱わないのでテンソルの考え方をわざわざ導入するよりも行列やベクトルと呼ぶ方がわかりやすいからでしょう。
ただ、ここで2次元、1次元、0次元のテンソルという概念を解説したのは人間の頭でイメージしやすいからです。ここからより高次元になるとだんだん想像が難しくなってきます。
グレースケールの画像
単色の画像は、モノクロ(Monochrome)と呼ばれます。モノクロ画像のデータは色の濃淡(強さ、Intensity)の値を2次元に配列したものです。
モノクロとは単色を意味するので色自体の指定はありません。つまり、どんな色としても解釈ができます。ただし、モノクロは黒から白へのグラデーション(色の変化)として表現されることが多いです。それをグレースケール(Grayscale)と呼びます。
![](https://assets.st-note.com/img/1679919236973-MPZ7UrmwLO.png)
また、画像上の各位置を画素あるいはピクセル(Pixel、Picture Element)と呼びます。ピクセルは画像データの最小要素です。モノクロ画像のデータではピクセルを指定すればその位置における色の濃淡値がわかります。
例えば、グレースケール画像では各ピクセル位置の値は白の強さを表します。データ型としては、8ビット(1バイト)がよく使われ、0から255までの整数値になります。0が完全な黒で、255が完全な白になります。全部で256段階の濃淡を表現できます。
![](https://assets.st-note.com/img/1679919237370-I1xV2TpVW0.png?width=1200)
つまり、モノクロの画像データは2次元に配列されたピクセルの濃淡値です。この画像データを$${\mathcal{M}}$$とすると、行と列(縦と横の位置)で指定したピクセルの濃淡値は、以下のように表現できます。
$$
\mathcal{M}[行,列] \rightarrow \text{濃淡値}
$$
行と列は0ベースのインデックスを使うので、2行3列目の濃淡値は$${\mathcal{M}[1,2]}$$と指定します。
このような2次元のデータ構造を画像のチャンネルと呼びます。この表現を使うと「モノクロ画像のデータは1つのチャンネルを持つ」と簡潔に言い換えられます。
RGBカラー画像
3次元のテンソルとして代表的なのはRGBのカラー画像です。
![](https://assets.st-note.com/img/1679917036925-Bojg5f2nCb.png?width=1200)
画像は2次元の正方形や長方形に敷き詰められたピクセル値の集まりです。ピクセル(Pixel)とはPicture ElementのPicとElを合体させて作った言葉です。画像データの最小要素になります。ピクセルの位置は行と列で指定することができます。
![](https://assets.st-note.com/img/1679917130963-nKFo2JSmpq.png?width=1200)
そう考えると2次元テンソルに思えますが、RGBのカラー画像では一つのピクセルに対して3つの色の値が指定されます。それは、赤(Red)、緑(Green)、青(Blue)のそれぞれの色の強さの値です。
![](https://assets.st-note.com/img/1679919380915-tdYcIVvNU3.png)
つまり、RGBの画像データは3つのチャンネルを持ちます。
![](https://assets.st-note.com/img/1679917258150-SVYj6uT62I.png?width=1200)
つまりRGB画像のピクセルはベクトルです。ベクトルは1次元のテンソルでした。よって、2つの軸でピクセルの位置を指定し、そのピクセルは3つの値を持つベクトルなので、全部で3次元が必要です。よって、RGB画像は3次元のテンソルです。
なお、ディープラーニングで使うRGBの画像は色の強さを0−255の整数値の範囲で指定することが多いです。つまり、上記の画像のように赤の強さが128、緑の強さが94、青の強さが32というように指定します。
0−255の整数値を使うのは1バイト(1Byte、あるいは8ビット)で値を指定するからです。より多くの色の範囲を指定するにはもっとバイト数を必要とし画像のデータを扱うのにより多くのメモリを必要とします。
0ー255の整数値だと数値が足りないのではと思われるかもしれません。しかし、一つの色の強さを256個の値で指定するので3つの色の組み合わせはかなり大きくなります。
$$
256 \times 256 \times 256 = 16,777,216
$$
これだけの色のバリエーションがあるので上記のような綺麗な画像も問題なく表現できています。なお、8ビットが3つあるので24ビットカラーとも呼ばれます。
3次元のテンソル
では、RGB画像を3次元のテンソルとして$${G}$$と表記しましょう。
![](https://assets.st-note.com/img/1679917828082-l3BFKhTNp5.png)
行480列180の位置にあるピクセルは$${G[480, 180]}$$と指定できます。これがRGBの値を含むベクトルを返すことになります。
$$
G[480, 180] \rightarrow [128, 94, 32]
$$
つまり、3次元のテンソルで2つの軸の値を指定したので残りの1軸の値が返されるわけです。
ちなみに同じ位置のピクセルの赤色の強さの値だけを取り出したければ次のように指定します。
$$
G[480, 180, 0] \rightarrow 128
$$
3次元のテンソルで3つの軸の値を指定したので返される値は0次元のテンソル(スカラー)になります。
同様に緑の色の強さの値は次のように取り出せます。
$$
G[480, 180, 1] \rightarrow 94
$$
青の色の強さの値も同じように取り出せます。
$$
G[480, 180, 2] \rightarrow 32
$$
なお3つ目の軸をチャンネル(Channel)と呼びます。RGB画像の場合、チャンネル数が3になります。
チャンネル・ファーストとチャンネル・ラスト
これまでチャンネル毎にデータが分かれている前提で話を進めてきましたが、実際にはRGB画像のデータ構造にはチャンネル・ファースト(Channel First)とチャンネル・ラスト(Channel Last)の2つの方式があります。
![](https://assets.st-note.com/production/uploads/images/101318187/picture_pc_47c839fb054950ec11eaf336268cd891.gif?width=1200)
チャンネル・ファーストでは、チャンネル→行→列と指定して濃淡値を得ます。以下のようにチャンネルを最初に指定する3次元配列で表現できます。
$$
\mathcal{M}[チャンネル,行,列] \rightarrow \text{濃淡値}
$$
例えば、赤・緑・青の各チャンネルのインデックスを 0,1,2 とすれば、赤のチャンネルの2行3列目の濃淡値は$${\mathcal{M}[0,1,2]}$$と指定します。
チャンネル・ラストでは、チャンネルを最後に指定します。
$$
\mathcal{M}[行,列,チャンネル] \rightarrow \text{濃淡値}
$$
よって、赤のチャンネルの2行3列目の濃淡値は$${\mathcal{M}[1,2,0]}$$と指定します。
また、ディープラーニングで画像を扱う場合はモノクロでもチャンネルを指定する形式で扱います。そうすればモノクロもRGBもチャンネルの数が異なるだけで同じ形式で扱えるからです。
例えば、モノクロ画像をチャンネル・ファーストで表現した場合、2行3列目の濃淡値は$${\mathcal{M}[0,1,2]}$$と指定します。ここでのチャンネル0は赤ではありません。モノクロ画像にある唯一のチャンネルであり、色の指定ではありません。同じく2行3列目をチェンネル・ラストで指定するならば$${\mathcal{M}[1,2,0]}$$となります。
チャンネル・ファーストかチャンネル・ラストかは使うソフトウェアによって異なるので注意してください。ちなみに、深層学習用のライブラリであるPyTorchはチャネル・ファースト、TensorFlowはチャンネル・ラストをそれぞれデフォルトで使います。
前述したように、RGB画像のデータ構造がチャンネル・ラストである場合、ピクセル位置を指定して3色の値をベクトルとして得ることができます。
$$
\mathcal{M}[行,列]→[赤の濃淡値、緑の濃淡値、青の濃淡値]
$$
これはチャンネル・ラストでは3色の濃淡値がメモリ上に連続で格納されているからです。
![](https://assets.st-note.com/production/uploads/images/101318922/picture_pc_7e53a34f58bcbaf6a3ae3456447e49e4.gif?width=1200)
ただし、ソフトウェアの機能としてメモリ上の構造に限らず、チャンネル・ファーストあるいはチェンネル・ラストによるデータへのアクセスを可能にすることもできます。よって必ずしもデータの格納構造とアクセス方法が一致するとは限りません。
画像データのバッチ
次に4次元のテンソルの例を見ましょう。代表的なのは複数の画像を一つのデータ構造にまとめた画像データのバッチです。
![](https://assets.st-note.com/production/uploads/images/101319904/picture_pc_14e0cc484a41574880aed4c10b9c304e.gif?width=1200)
画像のバッチでは最初の軸で画像を指定します。0が一番目の画像、1が2番目の画像、2が3番目の画像となります。画像一つ一つは3次元テンソルなので全部で4次元のテンソルとなります。
4次元のテンソルである画像のバッチを$${K}$$と呼ぶと$${K[1]}$$が2番目の画像になります。また、$${K[1]}$$は3次元のテンソルを返します。
この画像がチャンネル・ラストで扱えるとすると、2番目の画像の行130列50のピクセルの値は$${K[1, 130, 50]}$$でベクトル(1次元のテンソル)として取り出すことができます。
さらに、2番目の画像の行130列50のピクセルの赤の強さの値は$${K[1, 130, 50, 0]}$$でスカラー(0次元のテンソル)として取り出すことができます。
チャンネル・ファーストならば2番目の画像の行130列50のピクセルの赤の強さの値は$${K[1, 0, 130, 50]}$$で取り出すことができます。
まとめ
ディープラーニングで扱うデータはすべてテンソルとして扱います。よって、ディープラーニングのモデルが期待している入力データの構造をきちんと理解しておかないとうまく動作しないなどの問題が生じます。
つまり、次元数やチャンネルの数やチャンネル・ファーストとラストをきちんと把握しておく必要があります。
しかし、テンソルの概念自体は簡単なものです。この記事ではイメージしやすい例を使って4次元のテンソルまで解説しました。より高次元のテンソルになると想像するのが難しくなりますが、上述したようにデータ構造をきちんと把握していれば問題ありません。
テンソル同士の線形代数の計算などはライブラリが行ってくれます。次回はNumPyやPyTorchによるテンソルの計算を実際に行いましょう。
(続く)
この記事が気に入ったらサポートをしてみませんか?