検索
連載

Lesson 3 NumPyによる数学計算と、数学用語の「テンソル」機械学習&ディープラーニング入門(データ構造編)

NumPyのデータ構造「多次元配列」を使って数学計算を行う方法を説明。また、そもそも機械学習やディープラーニングでは、なぜ数学計算が重要になっているのかについても言及する。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「機械学習&ディープラーニング入門(データ構造編)」のインデックス

連載目次

ご注意:本記事は、@IT/Deep Insider編集部(デジタルアドバンテージ社)が「deepinsider.jp」というサイトから、内容を改変することなく、そのまま「@IT」へと転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。

 前回まで、AIプログラムで使うデータの構造に関して解説。基本的にはNumPyの多次元配列(ndarray)を使う、と説明した。今回は、そのndarray型のデータを使ってどのように計算するか、について説明しよう。脚注や図、コードリストの番号は前回からの続き番号としている。

 本稿で示すサンプルコードの実行環境については、Lesson 1を一読してほしい。

 Lesson 1でも示したように、本連載のすべてのサンプルコードは、下記のリンク先で実行もしくは参照できる。


Google Colabで実行する
GitHubでソースコードを見る

AIプログラムにおけるデータの計算

 これからNumPyの具体的な使い方、つまり計算方法を説明するわけだが、その前に、「ディープラーニングにおける計算」について知っておくべきことがあるので、それから順を追って説明させてほしい。

AI・ディープラーニングで数学を使う理由

 ディープラーニングの処理の中身は、さまざまな数式を使って、データの数値を幾重にも計算しながら変えていく処理、より直感的に表現するなら「数値をこねくり回すような処理」である。ディープラーニングの理論は数学を礎に築かれているわけで、その計算の大半を「NumPy」や「TensorFlow」のようなライブラリが肩代わりしてくれるとはいえ、その端々に、チラチラと数学の世界が垣間見えてしまうというのも現実である。

 しかもその数学は、大学レベルと比較的高度である。このように高度な数学を用いる理由は、計算を楽にするためでもある。具体例を出してみよう。人の身長(height)の平均(average)を計算するなら、リスト7-1のようなコードになる。

hana_height, taro_height, jiro_height = 165.5, 177.2, 183.2 # Lesson 1のリスト2-1で宣言済み

average_height = (
  hana_height + 
  taro_height + 
  jiro_height 
) / 3

print(average_height)  # 175.29999999999998

リスト7-1 3人の身長の平均を計算するコード例(個別の値を使用)
先頭行は、タプルと呼ばれる構文を使って、複数の変数にまとめて値を代入している。

Pythonの基本は1行1文であるが、カッコの中や+のような演算子の後は改行して文を継続できる。


 難しいところはないだろう。(+算術演算子を使って)身長を足し合わせた数値を、(/算術演算子を使って)3人で割ることで、身長の平均値(average_heightオブジェクト)を算出している。

 一見、こうやって計算すれば問題ないではないか、と思うかもしれないが、例えば3人ではなく、1000人や10万人ならどうだろうか? コードのボリューム(行数など)が333倍や3万倍とすごいことになってしまう。とても人間が書ける量ではなくなってくる。

 そこで役立つのが、ここまでに説明してきたデータ構造とその処理体系(具体的にはNumPyやTensorFlowなどが提供する「多次元リスト」「多次元配列」「データフレーム」「テンソル」などと、その計算機能)なのである。ちなみに、Lesson 1のリスト2-1で示したリスト型のところでも同じ理屈で、データをまとめる必要性を説明した。つまり、NumPyなどのフレームワークを活用して、データを多次元配列構造にまとめることは、単にデータが扱いやすくなるだけでなく、計算も効率的に行えるようになるということだ。

 試しに、上記のコードをNumPyの多次元配列を使って計算するコードに書き換えてみよう。

import numpy as np

array1d = np.array([ 165.5, 177.2, 183.2 ])

average_height = np.average(array1d)

average_height  # 175.29999999999998

リスト7-2 3人の身長と体重の平均を計算するコード例(多次元配列を使用)

 先ほどは(hana_height + taro_height + jiro_height) / 3と個別の値を使った計算式(=+/などの演算子)が書かれていた部分が、np.average(array1d)というNumPyの関数に書き換わっている。このarray1dオブジェクトは、NumPyの1次元配列(多次元配列の一種)である。つまりリスト7-2は、多次元配列を使った計算式(=np.average()関数)に書き換えられているというわけだ。

 繰り返しになるが重要なのでもう一度言うと、前掲のリスト7-1のような個別の値を使う場合だと、データの数が増えるほど、計算式部分のコードがどうしても長くなる。しかし、リスト7-2のような多次元配列を使う計算方法であれば長くならない。つまり多次元配列を使えば、計算式がシンプルで効率的になるのだ。

 そもそも、数学の発想そのものが、このように複雑で面倒くさい計算を、シンプルで効率的な短い式で表現しようとすることである。そのため、ディープラーニングのような計算を効率的に行うには、やはり「数学」の利活用が非常に重要ということになるのである。

AI・ディープラーニングで使われる数学用語

 このような理由から、データの計算では、数学が多用される。よって計算処理では、「個別の数値」や「多次元リスト」「多次元配列」のようなプログラミング用語ではなく、数学用語が用いられることが通例だ。具体的には、

  • 「個別の数値」は、「スカラー」(scalar)
  • 「1次元配列」は、「ベクトル」(vector)
  • 「2次元配列」は、「行列」(matrix)

と呼ばれる。高校数学の授業で「スカラー」や「ベクトル」は聞いたことがあるのではないだろうか。

 「行列」については、2012年度から高校数学で扱わなくなっているので、大学で学んでいない場合は知らないかもしれない。しかし難しいことはない。Lesson 1と2で学んだ多次元リスト(もしくは多次元配列)のうち、「2次元」のものが、「行列」である。行列の計算方法は、NumPyやTensorFlowに任せればよいので、とりあえず知らなくても大丈夫だ。

 また、「3次元配列」以上の多次元配列に対応する数学は、大学で学ぶ。具体的には、

  • 「多次元配列」は、「テンソル」(tensor)

と呼ばれる。「テンソル」は、TensorFlowのデータ構造の概念と同名である、と前回Lesson 2ですでに説明した。ここでようやく、

Pythonの「多次元リスト」 = NumPyの「多次元配列」 = TensorFlowの「テンソル」

と意味がつながる。つまりTensorFlowでは、データ構造に対して単に数学寄りの命名をしているというだけだ。単なる用語・名称の違いでしかないので、「テンソル……うわぁ、数学か……」と難しく考えすぎないようにしてほしい。場面場面によってこれらの用語は使い分けられるので、用語の違いは単純に記憶するしかない。

 なおテンソルにも、プログラミング用語で言う「1次元・2次元・3次元……」といった「次元」(dimensions)対応する数学用語がある。それが「」(ランク、階層)である。具体的には、

  • 「個別の数値」は、「0階のテンソル
  • 「1次元配列」は、「1階のテンソル
  • 「2次元配列」は、「2階のテンソル
  • 「3次元配列」は、「3階のテンソル
  • 「N次元配列」は、「N階のテンソル

のように表現する。

 ここまで用語がたくさん登場したので、一覧表と図にまとめた。ぜひ、いま一度、頭の中を整理しておいてほしい。

Python(多次元リスト) NumPy(多次元配列) TensorFlow/数学用語(テンソル) 数学用語(値)
個別の数値 0次元配列 0階のテンソル スカラー
1次元リスト 1次元配列 1階のテンソル ベクトル
2次元リスト 2次元配列 2階のテンソル テンソル
3次元リスト 3次元配列 3階のテンソル テンソル
N次元リスト N次元配列 N階のテンソル テンソル
表1 多次元配列に類する各種用語

多次元配列と数学用語の関係図
図8 多次元配列と数学用語の関係図

 数学とNumPyの関係が分かったので、NumPyの数学計算について簡単に機能を紹介しておこう。

NumPyの数学計算機能

 前掲のリスト7-2ではnp.average(array1d)というコードで、npと名付けたnumpyモジュールのaverage()関数を呼び出していた。基本的にNumPyはこのように、関数の引数に多次元配列のndarrayオブジェクトを受け取り、計算結果を戻り値として返す。つまり、

<戻り値は計算結果> = <計算を行う関数名>(<多次元配列のデータ>)

という仕様になっている。

 どのような数学系の関数があるかというと、代表的なものは以下のとおりだ。なお、これらすべての計算式を覚える必要はない。必要になった段階で、調べて使えばよい。

  • 四則演算: 足し算:add()、引き算:subtract()、掛け算:multiply()、割り算:divide()、余り:mod()Python言語と同様に + - * / % も使える
  • 丸め処理: 切り捨て:floor()、切り上げ:ceil()、四捨五入:round()
  • 三角関数: サイン:sin()、コサイン:cos()、タンジェント:tan()
  • 数学概念: 絶対値:absolute()、累乗:power()、平方根:sqrt()、指数:exp()、対数:log()
  • 数学定数: 円周率π:pi、ネイピア数e:eこれらは関数ではなく定数
  • 統計処理: 合計:sum()、平均:average()、最小値:amin()、最大値:amax()、標準偏差:std()、分散:var()

 数学の計算式は多種多様で、ここで取り上げたものはほんの一部である。詳しくは、NumPyの公式APIリファレンス数学関数統計関数を参照してほしい(ただし、英語ページしかないので、日本語で読みたい場合はGoogle検索や翻訳などを活用して、必要な計算を探すしかない)。

NumPyを使った計算

 これだけだと分からない部分も多いと思うので、NumPyによる数学計算の例をもう少し見ておこう。

 まずは、3行2列の2次元配列を作成してみよう。リスト8-1は、その配列の形状(=shape)と次元数(=ndim)と要素*5数(=size)を出力している例だ。

array2d = np.array([ [ 165.5, 58.4 ],
                     [ 177.2, 67.8 ],
                     [ 183.2, 83.7 ] ])

print(array2d.shape)  # (3, 2)
print(array2d.ndim)   # 2
print(array2d.size)   # 6

リスト8-1 3行2列の行列のさまざまな特性を表示するコード例

*5 プログラミングでは、配列内の個別の値は要素(element)と呼ぶが、数学の行列では成分(entry)とも呼ぶ。計算においては、数学に寄せて「成分」と記載している本も多いので注意してほしい。ちなみに、数学の行列は、大学数学では線形代数と呼ばれる分野に入る。


 リスト8-2は、体重を90%にするダイエット目標を計算する例だ。数学や計算式の意味は本筋ではないので説明しないが、数学の行列の転置(T)や積(@:Python 3.5以降の場合。それ以前のPython 2系などの場合はmatmul関数)を使って計算している(意味は分からなくてよい。ここでは行列計算が簡単にできることを知ってほしいだけだから)。

diet = np.array([ [ 1.0, 0.0 ],
                  [ 0.0, 0.9 ] ])

lose_weights = diet @ array2d.T
# Python 3.5以降の場合。それ以前のPython 2系などの場合は、以下のmatmul関数を使う必要がある
#lose_weights = np.matmul(diet, array2d.T)

print(lose_weights.T)  # [[165.5   52.56]
                       #  [177.2   61.02]
                       #  [183.2   75.33]]

リスト8-2 NumPyを使った行列計算

 このような感じで行列計算できる。

 もう一つ例を見ておこう。身長や体重の平均値を2次元配列(=行列)の状態で計算してみよう。

Copyright© Digital Advantage Corp. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る