Neural Networkの行列式 (ディープラーニング Step IV)

前回、ニューラルネットワーク(Neural_Network)を連立式で実装することを記事にしました。  今度は、その連立式を行列演算にしてみます。 Pythonが基本的に扱う配列は1次元のリストです。 PythonにNumpyモジュールをインストールすると多次元の配列が扱えるようになります。 そして、Numpy ではベクトル演算として内積(dot)やその他の行列演算が可能となります。 行列演算が使えると、ベクトル積や回転演算が可能となるので画像処理で必要となる変換演算が簡単になります。 ただ、Pythonの配列が図や写真データを配列データとしても扱うものであり、行列のために有るわけでないということです。 行列演算を実装するには、注意が必要と思います。今回の記事は、プログラムでの配列の扱いと行列演算の違いにも少し注目してみたいと思います。

1. 連立方程式と行列演算

 ディープラーニングのプログラミングには行列計算が欠かせなということです。 しかし、近年の高校数学課程からは行列の単元が無くなっているらしいです。 このためでしょうか、機械学習やディープラーニングの入門書籍には、行列計算の基礎を簡単に解説をしています。 ここでは、行列の計算は線形代数の書籍[*1]で基礎から高度な利用まで解説されていますので、プログラムで使う基本的な説明を簡単にするだけにします。


  連立方程式は、簡単には、鶴亀算を方程式にします。 例えは、「鶴と亀が合わせて28頭います。それぞれの足の和は86になるとき、鶴と亀は何頭ずついるでしょうか?」。  鶴を x頭、 亀を y頭 として、  これを連立方程式にすると、次の式(IV-1)となります。

となります。

 これを行列を使って書き直すと次のようになります。 

 行列式を見慣れないと面倒な式に見えますが、等号(=)の左には、4つの要素からなる2行2列の行列と、x、yの変数を縦に並べた縦ベクトル記載することで、(IV-1)の連立方程式と同じ式を表示ししています。

( 1次配列の場合はベクトルという変数の群になります。 ベクトル要素の並べ方で縦ベクトルまたは横ベクトルと呼びます。 1列だけの行列列が縦ベクトルであり、1行だけの行列が横ベクトルとして扱えます。 行列とベクトル並べることで、行列変換が表現されます。 行列演算の記載方法として行列とベクトル間に記号[・]を入れることもあります。 この記号[・]がNumpyの内積コマンドの'dot'になります。)

 数学では、式(IV-1)は x と y の値(鶴と亀の頭数)を求める連立方程式の問題として習います。 式(IV-1)の方程式の解法には、色々な方法がありますが、 式(IV-2)の行列式を使う解法では、行列の逆行列を作り、行列式の左側から逆行列演算をかける x と y が答えとして導けます。 ( 線形代数における”行列解法”は、ここのディープラーニングの目的とは離れるので、解法説明は省略します。線形代数の教本[*2など]で自習いただきたいです。 答えは鶴13頭、亀15頭です。)


2.プログラムにおける行列演算

 線形代数の3元連立方程式、式(IV-3)を考えます。

これを行列表記すると

式(IV-4)の x,y,z は縦に並べた3行1列配列の縦ベクトルです。 行列の積のルールからは、式(VI-4)の様に、3個の変数 x, y, z は縦ベクトルにして行列の右側に置く時には、行列の列数が変数の数=3、(式(VI-2)の場合は2) に一致する必要があります。  数学問題としては、'='の右辺と左辺が同じとして解(x, y, z)を求めることが目標となりますが、 プログラムでの '=' は、右辺の値を左辺に代入することです。 (式(IV-3)をそのままプログラムに記載しても条件式になるので、真偽判定になってしまう? Pythonの条件式で、両辺が等しい場合は '==' を使いますので、答え合わせなら、この条件式でもいいかもしれない。) 

 プログラムとしては、演算の結果を配列Aに代入するという演算式とすれば、次の式(VI-5)となります。 線形代数としては、式(VI-5)と式(VI-3)は同じものと考えられます。

これを行列式に直せば、

となります。 プログラムから見た場合、式(IV-6)の出力( a1, a2, a3 )や、変数( x, y, z )は縦ベクトル、1行3列の配列と見なすことが出来ます。 Numpy アレイなら [ [ a1], [ a2], [ a3 ] ]や[ [ x ], [ y ], [ z ] ]となります。しかし、プログラム上では横ベクトルとして[ a1,  a2,  a3 ]や[ x, y, z ]の配列で扱いたいです。 プログラムでは縦ベクトルを扱うのは苦手です 【私見ですけどネ】 。 

 そこで、入力変数[ x, y, z ] と出力[ a1, a2, a3 ] を横ベクトルにして式(IV-6)を直すと式(IV-7)となります。

入力変数を3変数の横ベクトルにすると、行列はその演算ルールから入力ベクトルの右側に並べることになります。 そして、行列の要素の位置が斜め下方向を軸にして対象位置に入れ替わります。

 行列で言うところの転置行列です。 行列の要素Wijで確認すると、i を出力の結果に一致させ、 j を入力変数の添え字に一致させています。

 (線形代数の連立方程式の勉強から行列に入った私には、入力・出力を縦ベクトルで記載することに慣れているので、行列要素も書き方が転置関係にあります。 違和感が有りますので、少し注意が必要です。) 


ニューラルネットワークの行列と、線形代数の行列の違いを紹介してしまったのですが、 ニューラルネットワークの行列処理に話を戻します。


3. ネットワークの行列の積  

Numpy のdot 演算を使えば、ベクトルと行列の積、または行列と行列の積が計算できます。  前回の3層のネットワークフロー図を行列式で示すことにします。  

まずは、図(III-9)ネットワークフローです。

 1段目を行列式で書くと式(IV-8)となります。 入力変数と出力は横ベクトルにしました。

  ネットワークフローの2段目は下の式(IV-9)の1行目になります。 これに、式(IV-8)を代入することで2行目の式になります。

 さらに、フローの3段目は式(IV-10)の1行目になり、式(IV-9)を代入すると2行目になります。

 この様に、初期入力を横ベクトルにすると、演算子としての行列は右側に追加されていく事になります。  (もし、初期入力を縦ベクトルにすると、演算行列は左側に追加されていきます。)

  少し、早いようですが、ネットワークフローの行列式はここまでです。 


3.行列式を描くプログラム

 この記事では、ニューロネットワークの行列演算式を紹介しました。 行列演算を実装するにはNumpyに演算子がありますので簡単そうです。 次回分に合わせて実装プログラムを作ることにしました。

 今回は、行列式を描くプログラムをPython で作ることにチャレンジしました。 最初、Matplotlib のTexで、genfrac 関数を使う方法の範囲で探索してみましたが、2行の行列は書くことは出来ますが、3行になるとどうしたらいいのか分からなくなりました【私の力足かも】。  多分、LaTex ならば綺麗に行列が描けるようですが、使っていませんので、よく分かりません。 この際なので、プログラム化してみることにしました。


1) 行列を描く関数 plot_matrix

行列を描くために、関数 plot_matrix を作りました。 式の描き出しの位置をX_pos,Y_pos(1、2番目)の引数として関数に渡します。 描いた行列の右側の位置を関数の戻り値として、直ぐ右側に次の行列を描けるようにします。 その他の引数として、(3)行列要素の配列、(4)行列の種類('M','m' は通常の行列、'H','h' は縦ベクトル、'V','v' は横ベクトル、'S','s'は括弧なし)、(5)行列中の1要素の幅(文字数で指定)、(6)文字サイズ とします。 

【関数定義の部分】 プログラムとしてはそれほど難しくはなったのですが、文字サイズと各要素を描く位置の関係には、パラメータを何回も調整を繰返して、適当な値を探った結果です。  パラメータとしては [ x_rate, y_rate ] は、文字の大きさをプロットの大きさに変換する変換率、  [ x_space, y_space ]は、行列の各要素の間に取るスペースの文字数、  [ row , col ]は行列の行と列の数( 行列だけでなく、縦や横の1次元ベクトルでも設定できるようにした) 、  [ S ]は、行列の左右に記載する( )のフォントサイズ(行列の行数で変わります)を表します。 工夫点としては  (1) 2次元行列と1次元ベクトルを同様に扱うために、flatten() 関数で1次元配列に統一しています。   (2)Y(縦)方向の位置は、Y_pos を中央にして行数に応じた位置を計算して決めています。

プログラム(IV-2) : 式(IV-2)を描く

 まず、基本的な行列式(IV-2)を描くプログラムを紹介します。 前半が関数部分となり、後半が主プログラム部分となります。  

2) 主プログラム部分

【主プログラム部分】 プログラム(IV-2)の後半の主プログラムでは、 行列式の描きだしの位置(X=0,y=0.8)を決めて、行列の要素2×2配列([['1','1'],['2','4']]) を関数を使って描きます。 次に入力の変数(['x','y'])を縦ベクトルを関数で描き、 等号(['='])を1文字だけの配列として括弧なしでを関数で描きます。 続けて、出力(['28','86'])を縦ベクトルをを関数で描いています。 関数を使うと、横方向の描き始めの位置 X_pos を戻り値にするので、直ぐに、右に描く次の行列を描くことが出来ます。

主プログラム(IV-1): 式(IV-1)を描く

 先ほどのプログラム(IV-2)の主プログラムの所を以下のプログラム(IV-1)で書き換えます。 式(IV-1)は連立方程式ですが、パラメータをSとして括弧()のない行列として2段に描くことができます。 ただし、大きな括弧 { 記号は別に記載するようにします。(括弧の種類によって、幅設定を調整する必要が有るためです) 

主プログラム(IV-3): 式(IV-3)を描く主プログラム部分

主プログラム(IV-4): 式(IV-4)を描く主プログラム部分

主プログラム(IV-5): 式(IV-5)を描く主プログラム部分

主プログラム(IV-6): 式(IV-6)を描く主プログラム部分

主プログラム(IV-7): 式(IV-7)を描く主プログラム部分

主プログラム(IV-8): 式(IV-8)を描く主プログラム部分

主プログラム(IV-9): 式(IV-9)を描く主プログラム部分

主プログラム(IV-10): 式(IV-10)を描く主プログラム部分

として、色々な行列式を描くことが出来ます。


4. あとがき

今回は、行列演算によるニューラルネットワークの説明と、行列式を表記するプログラムの実装をしてみました。 ディープラーニングとしてはあまり進捗が有りませんでしたが、 行列要素の配置ルール(添え字の付け方も)が、線形代数での習慣的な取り扱いと少し違う点が理解できたことは個人的には得るものでした。 また、行列を描く関数を作ることが出来たので、今後の処理には役立つと思っています。


参考文献 / 参考リンク :  

*1) このブログは教本として、ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装 [ 斎藤 康毅 ] 【出版社: オライリージャパン 発売日: 2016/9/24 】 (ISBN-10:4873117585 ISBN-13:978-4873117584) を使っています。

2) 線形代数での行列については各種の専門書が有ります。 基本的で分かり易い本として 高校数学でわかる線形代数 (ブルーバックス) [ 竹内 淳 ]  などがあります。

3) Pythonでの描画はmatplotlibを使用します。matplotlib サイト のチュートリアルは機能を調べるのには便利でした。 例えば、Tutorials » Annotations(注釈)辺りから調べます。https://matplotlib.org/tutorials/text/annotations.html#sphx-glr-tutorials-text-annotations-py

* ) 独学ではなかなか進まない方は、やはり有料になりますが、専門セミナーを受けられることをお勧めします。  


  __ __ __~~~( ゜〈‶   __ __ __ ~~( ゜〈‶     🐭    "〉゜ )~~python __ __ __




初心者がPythonでプログラミング入門。初歩からデープラーニングを体験的に学習する記録

プログラム初心者でも解るように説明をしながら、これからの時代に必要なPython(パイソン)を使って、プログラミング入門から初めてAIデープラーニングを体験的に学習するサイトです。主の教科書に「ゼロから作るDeep Learning 」(オライリージャパン)を使って、多くの情報サイトを使います。自主学習の記録として留めておきたいこと、これから学習する人が知りたいだろうことをブログ式にまとめています

0コメント

  • 1000 / 1000