2017年5月17日
ディープラーニングのための線形代数入門:一般的演算の初学者向けガイド
(2017-03-05)by Brendan Fortuner
本記事は、原著者の許諾のもとに翻訳・掲載しております。
Jeremy Howardによる ディープラーニングの素晴らしいコース を受講している間、自分の前提知識がさびついてきているせいで、誤差逆伝播法のような概念が理解しにくくなっていることを認識しました。そこで、理解度を上げるべく、そうした概念に関するいくつかのWikiページをまとめてみることにしました。本記事では、ディープラーニングでよく使われる線形代数演算のいくつかについて、ごく基本的な事項をざっとご紹介します。
線形代数とは?
ディープラーニングの文脈での線形代数とは、数の集合を同時に操作するための便利な手法を提供してくれる、数学的ツールボックスです。これらの数値を保持するためのベクトルや行列(スプレッドシート)のような構造体と、それらを加算、減算、乗算、および除算するための新しい規則を提供します。
線形代数が便利な理由
線形代数は、複雑な問題を単純で直感的に理解できる、計算効率の良い問題に変換してくれます。以下は、線形代数を使えばいかに高速で単純な解法を導くことができるかを示す例です。
# 2つの配列を掛ける
x = [1,2,3]
y = [2,3,4]
product = []
for i in range(len(x)):
product.append(x[i]*y[i])
# 線形代数バージョン
x = numpy.array([1,2,3])
y = numpy.array([2,3,4])
x * y
配列の初期化後で比較すると、線形代数を使った方法は3倍の速さでした。
ディープラーニングでの活用法
ニューラルネットワークは、行列の重みを格納します。線形代数は、特にGPUのトレーニング時の行列演算を高速かつ簡単にしてくれます。実は、GPUはベクトルと行列の演算を念頭に置いて作られたのです。画像がピクセルの配列として表現されるのと同様、ビデオゲームは進化し続ける巨大な行列を使って魅力的なゲーム体験を生み出します。GPUは、ピクセルを1つずつ処理するのではなく、ピクセルの行列全体を並列処理するのです。
ベクトル
ベクトルは数や項の1次元配列です。幾何学において、ベクトルは点の位置変化の大きさと方向を格納します。ベクトル[3, -2]は、右に3、下に2進むことを示します。1次元以上のベクトルは行列と呼ばれます。
ベクトルの記法
ベクトルを表現するには様々な方法があります。以下は、皆さんが目にする記法の数例です。
幾何学におけるベクトル
ベクトルは一般的に、点からの移動を表現します。点の位置変化の大きさと方向を格納するのです。ベクトル[-2, 5]は、左に2単位、上に5単位進むことを示します。( 出典 )
v =[-2, 5]
ベクトルは空間のどの点にも適用できます。ベクトルの方向は、上に5、左に2移動する際に作られる斜辺の傾きと一致します。ベクトルの大きさは、その斜辺の長さと一致します。
スカラー演算
スカラー演算では、ベクトルと数が含まれます。ベクトルの全ての値に対して加算や減算、乗算を行い、ベクトルをインプレースで変化させます。
スカラーの加算
要素ごとの演算
加算、減算、除算などの要素ごとの演算においては、対応する位置の値を組み合わせて新しいベクトルを求めます。ベクトルAの1つ目の値はベクトルBの1つ目の値と、2つ目の値は2つ目の値といった要領です。つまり、演算が完結するには、ベクトルの次元が一致している必要があるのです(※)。
ベクトルの加算
y = np.array([1,2,3])
x = np.array([2,3,4])
y + x = [3, 5, 7]
y - x = [-1, -1, -1]
y / x = [.5, .67, .75]
(※)NumPyにおける ブロードキャスト の詳細については、後出のセクションをご参照ください。
ベクトルの乗算
ベクトルの乗算には、内積とアダマール積の2種類があります。
内積
2つのベクトルの内積は、1つのスカラーとなります。ベクトルや行列の内積(行列の乗算)は、ディープラーニングにおいて非常に重要な演算です。
y = np.array([1,2,3])
x = np.array([2,3,4])
np.dot(y,x) = 20
アダマール積
アダマール積は要素ごとの乗算であり、その結果は1つのベクトルとなります。
y = np.array([1,2,3])
x = np.array([2,3,4])
y * x = [2, 6, 12]
ベクトル場
ベクトル場は、加算や乗算などのベクトル関数を適用した場合に点(x,y)が仮説上どこまで移動するかを示します。空間に点がある時、ベクトル場は、グラフの様々な点において働く変化の 力 と 方向 を示します。
このベクトル場は、始点によって移動方向が異なるという点で興味深い概念です。始点ごとに移動方向が違う理由は、この場の背後にあるベクトルが、-2や5のようなスカラー値ではなく $ 2x $ や $ x^2 $ のような項を格納するからです。グラフの各点について、x座標を $ 2x $ や $ x^2 $ に代入して、始点から新しい位置までの矢印を描いているのです。ベクトル場は、勾配降下法のような機械学習の手法を可視化するのに大変有用です。
行列
行列とは、加算、減算、乗算の特別な規則を持った、数や項から成る長方形の配列(Excelシートのイメージ)です。
行列の次元
行列の次元は 行×列 で記述します。
a = np.array([
[1,2,3],
[4,5,6]
])
a.shape == (2,3)
b = np.array([
[1,2,3]
])
b.shape == (1,3)
行列のスカラー演算
行列に対するスカラー演算は、ベクトルに対する場合と同様に行います。加減乗除などは、行列の全要素に対して単純にスカラーを適用します。
行列のスカラー加算
a = np.array(
[[1,2],
[3,4]])
a + 1
[[2,3],
[4,5]]
行列の要素ごとの演算
2つの行列間で加算、減算、除算を行うには、両者の次元が同じである必要があります(※)。対応する要素の値を組み合わせて、新しい行列を求めます。
a = np.array([
[1,2],
[3,4]
])
b = np.array([
[1,2],
[3,4]
])
a + b
[[2, 4],
[6, 8]]
a — b
[[0, 0],
[0, 0]]
NumPyのブロードキャスト(※)
これは実作業に大いに関わることなので、触れないわけにはいきません。NumPyでは、 ブロードキャスト と呼ばれるメカニズムを使うことで、要素ごとの演算に対する次元要件が緩和されています。各行列の対応する次元(行と行、列と列)が以下の要件を満たしていれば、その2つの行列同士は演算可能です。
- 次元が等しい。または、
- 1次元のサイズが1である。
a = np.array([
[1],
[2]
])
b = np.array([
[3,4],
[5,6]
])
c = np.array([
[1,2]
])
# 行数が同じ
# 列数が違う
# しかし、aは1列なので動きます
a * b
[[ 3, 4],
[10, 12]]
# 列数が同じ
# 行数が違う
# しかし、cは1行なので動きます
b * c
[[ 3, 8],
[5, 12]]
# 列数が違う
# 行数が違う
# しかし、aとcの両方が
# サイズが1であるという要件を満たす
a + c
[[2, 3],
[3, 4]]
3次元や4次元といった高次元では状況が不可解になっていきますが、当面は気にしないでおきましょう。2次元の演算を理解することがいい取り掛かりとなります。
行列のアダマール積
行列のアダマール積は、要素ごとの演算です。対応する位置の値を掛け合わせて新しい行列を求めます。
a = np.array(
[[2,3],
[2,3]])
b = np.array(
[[3,4],
[5,6]])
# Pythonの乗算演算子を使用します
a * b
[[ 6, 12],
[10, 18]]
NumPyでは、行列とベクトルのアダマール積は、両者の次元がブロードキャストの要件を満たす限り、求めることが可能です。
行列の転置
ニューラルネットワークでは、行列の乗算の要件を満たさない異なる場合、次元の重みや入力を頻繁に処理します。行列の転置は、乗算の要件を満たして演算を続行できるよう、行列の1つを「回転」する方法を提供します。行列の転置は以下の2段階で行います。
- 行列を右に90度回転する。
- 各行の要素の順序を反転する(例:[a b c]は[c b a]となる)。
例えば、以下の行列 M を転置すると行列 T になります。
a = np.array([
[1, 2],
[3, 4]])
a.T
[[1, 3],
[2, 4]]
行列の乗算
行列の乗算では、行列同士を掛け合わせて新しい行列を求めるための規則があります。
規則
全ての行列で乗算を行えるわけではありません。さらに、結果の行列の次元に関する規定があります。( 出典 )
- 1つ目の行列の列 数と 2つ目の行列の行 数が同じである。
- M×N行列とN×K行列の積はM×K行列である。新しい行列の行数は 1つ目の行列の行数 、列数は 2つ目の行列の列数 となる。
手順
行列の乗算では、内積によって行と列の様々な組み合わせを掛けます。Khan Academyの素晴らしい線形代数コースから引用した以下の画像を見ると、行列Cの各要素は行列Aの行と行列Bの列の内積となっていることが分かります。
演算a1 · b1は、行列Aの1行目(1, 7)と行列Bの1列目(3, 5)の内積となります。
以下の例もご覧ください。
例題で理解度をチェックしよう
注釈
What are the dimensions of the matrix product?:行列の積の次元は?
What is the matrix product?:行列の積は?
NumPyを使った行列の乗算
NumPyでは、ベクトルの乗算と行列の乗算のいずれにも関数 np.dot(A,B)
を使います。この関数には、他にも興味深い機能や注意点がありますので、使う前に こちら のドキュメントを読んでおくことをお勧めします。
a = np.array([
[1, 2]
])
a.shape == (1,2)
b = np.array([
[3, 4],
[5, 6]
])
b.shape == (2,2)
# 掛ける
mm = np.dot(a,b)
mm == [13, 16]
mm.shape == (1,2)
チュートリアル
Khan Academyの線形代数
書籍『Deep Learning』の数学のセクション
Andrew Ngのコースノート
線形代数の説明
行列の説明
線形代数の概要
immersivemath (没入型の数学)