トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索   ヘルプ   最終更新のRSS

MATLAB Note/Neural Network Toolbox/SOM(自己組織化マップ) の変更点

Top / MATLAB Note / Neural Network Toolbox / SOM(自己組織化マップ)

#freeze
#access
#analog

-目次
#contents

**自己組織化マップ(Self-Organizing Maps, SOM) [#c502a786]
-リファレンス
--[[競合学習ネットワーク:http://www.mathworks.com/access/helpdesk_archive_ja_JP/r13/help/toolbox/nnet/selforg3.html#69]]~
--[[自己組織化マップ:http://www.mathworks.com/access/helpdesk_archive_ja_JP/r13/help/toolbox/nnet/selforg9.html#10542]]
--[[デモンストレーション:http://www.mathworks.com/access/helpdesk_archive_ja_JP/r13/help/toolbox/nnet/c_demos6.html#3918]]
--[[サブプロパティ net.layers のリファレンス:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/netobj18.shtml#2515]](トポロジー関数、距離関数)
--[[トポロジー関数、距離関数のカスタマイズ:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/adv1213.shtml#9831]]
~
***学習に使用するデータ [#jeb2f023]
-入力として使うのは、おなじみのあれ((Teuvo Kohonen (1995).『Self-Organizing Maps』, Springer. (徳高平蔵・堀尾恵一・堀尾正昭・大薮又茂・藤村喜久郎訳(2003). 自己組織化マップ.『シュプリンガー・フェアラーク東京』.).))です。~
あれ → 
&ref(http://shower.human.waseda.ac.jp/~m-kouki/matlab/animal.JPG);~
--横軸の特徴量の数は、入力層の要素(ノード)数に対応します。
--縦軸の1行が、逐次型(適応)学習の1回のステップで与えられる入力ベクトルに対応します。
--また、この13×16の入力ベクトルセットが、バッチ型(訓練)学習の1回のエポックで与えられる入力ベクトルに対応します。


***基本SOM(単層) [#uef1e63e]
-まずは、Neural Network Toolbox での基本SOMの実装についてまとめておきます。
--ここで作成するSOMは、5×4の二次元マップとします。
-まずは入力値と、入力値のラベル(それぞれのデータ名)を宣言します。~
#geshi(matlab){{
 P = [
     1 0 0 1 0 0 0 0 1 0 0 1 0
     1 0 0 1 0 0 0 0 1 0 0 0 0
     1 0 0 1 0 0 0 0 1 0 0 1 1
     1 0 0 1 0 0 0 0 1 0 0 1 1
     1 0 0 1 0 0 0 0 1 1 0 1 0
     1 0 0 1 0 0 0 0 1 1 0 1 0
     0 1 0 1 0 0 0 0 1 1 0 0 0
     0 1 0 0 1 1 0 0 0 0 1 0 0
     0 1 0 0 1 1 0 0 0 0 1 0 0
     0 1 0 0 1 1 0 1 0 1 1 0 0
     1 0 0 0 1 1 0 0 0 1 0 0 0
     0 0 1 0 1 1 0 0 0 1 1 0 0
     0 0 1 0 1 1 0 1 0 1 1 0 0
     0 0 1 0 1 1 1 1 0 0 1 0 0
     0 0 1 0 1 1 1 1 0 0 1 0 0
     0 0 1 0 1 1 1 0 0 0 0 0 0
 ]
 Plabel = strvcat('ハト','メンドリ','アヒル','ガチョウ','フクロウ','タカ','ワシ','キツネ',...
    'イヌ','オオカミ','ネコ','トラ','ライオン','ウマ','シマウマ','ウシ') %STRVCAT 文字列を垂直に結合
 
 %行と列を転置
 P = P';
}}

--MATLABの仕様では、ネットワークへの入力ベクトルは、行成分を特徴量、列成分を1つの入力データにする必要があります(上図の逆です)。そのため、最後に行と列を転置しています。

-関数 NETWORK の引数にするために、作成した入力ベクトルのサイズを調べておきます。
#geshi(matlab){{ 
 % 入力ベクトルの行数(Y 軸のサイズ、特徴量の数)、列数(X 軸のサイズ、データセットの数)を調べる
 [ipSizeY,ipSizeX] = size(P)
 % 入力層の要素の範囲を生成
 iprange = [min(P') ; max(P')]';   %[最小値 最大値]を特徴量の数だけ行方向に連結
}}

-続いて、新規のネットワークオブジェクトを生成して、SOMの固有プロパティを宣言します。
#geshi(matlab){{
 opSizeX = 5;            %SOM の X 軸(横軸、列成分)のセル数
 opSizeY = 4;            %SOM の Y 軸(縦軸、行成分)のセル数
 
 % ネットワークアーキテクチャ
 net = network(1,1,[0],[1],[0],[1],[0]);             %新規のネットワークを作成
 % 引数 : 入力数 = 1、層の数 = 1、層 1 はバイアスをもたない、層 1 は入力からの重みをもつ、
 %        層 1 は他層との重みをもたない、層 1 は出力をもつ、層 1 はターゲットをもたない
 
 % 入力層の要素の範囲
 net.inputs{1}.range = iprange;                      %入力ベクトルのサイズ(13×2)
 % 層 1 の物理的な次元
 net.layers{1}.dimensions = [opSizeX opSizeY];       %SOM の X, Y,..軸それぞれのセル数
 % 層の次元から層 1 のニューロンの位置を求めるトポロジー関数
 net.layers{1}.topologyFcn = 'gridtop';              %GRIDTOP(格子状層トポロジー関数) 
 % ニューロンの位置から層 1 のニューロン間の距離を求める距離関数
 net.layers{1}.distanceFcn = 'boxdist';              %BOXDIST(2つの位置ベクトル間の距離)
 % 入力層から層 1 への重み関数
 net.inputWeights{1,1}.weightFcn = 'negdist';        %NEGDIST(正規化列重み初期化関数)
 % 層 1 の伝達関数
 net.layers{1}.transferFcn = 'compet';               %COMPET(競合伝達関数)
 
 % 入力層から層 1 への重み行列の更新関数(学習関数)
 net.inputWeights{1,1}.learnFcn = 'learnsom';        %LEARNSOM(SOM重み学習関数)
 % LEARNSOMのパラメータを指定
 net.inputWeights{1,1}.learnParam.order_lr = 0.9;     %順序付けフェイズの学習比(デフォルト)
 net.inputWeights{1,1}.learnParam.order_steps = 1000; %順序付けフェイズのステップ数(デフォルト)
 net.inputWeights{1,1}.learnParam.tune_lr = 0.02;     %調整フェイズの学習比(デフォルト)
 net.inputWeights{1,1}.learnParam.tune_nd = 1;        %調整フェイズの近傍距離(デフォルト)
 
 % 適応関数
 net.adaptFcn = 'trains';                            %TRAINS(重みとバイアスによる)
 % 訓練関数
 net.trainFcn = 'trainr';                            %TRAINR(ランダムな順番での逐次型訓練)
 
 % 初期化(Initialization)
 net.initFcn = 'initlay';                            %INITLAY(層ごと)
 % 層 1 を初期化するために用いる関数
 net.layers{1}.initFcn = 'initwb';                   %INITWB(重みとバイアスによる)
 % 入力層から層 1 への重み行列初期化関数
 net.inputWeights{1,1}.initFcn = 'midpoint';         %MIDPOINT(中間点重み初期化)
 net = init(net);                                    %初期化を実行する
}}

--「''トポロジー関数(topologyFcn )''」とは、SOMの層上のノードの配置形式のことで、ここでは[[GRIDTOP:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/gridtop.shtml]](四角形に配置)を指定しています([[詳細:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/selfor10.shtml]])。
--「''距離関数(distanceFcn )''」とは、SOMの層上のノード同士の距離の計算方法のことで、ここでは[[BOXDIST:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/boxdist.shtml]](四角形の座標で計算)を指定しています([[詳細:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/selfo11a.shtml]])。
--伝達関数(各ノードの出力)には、[[COMPET:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/compet.shtml#498970]](勝利ノードのみ 1 を出力)を指定しています([[参考:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/selforg3.shtml#69]])。その他の伝達関数として、デフォルトでは[[SOFTMAX:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/softmax.shtml#669443]](最大の入力をもつノードは1に最も近い値を出力、それ以外は0に近い値を出力)が用意されています。
--学習関数(各ノードの重み付け変更)には、[[LEARNSOM:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/learnsom.shtml#500592]]を指定しています([[詳細:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/selfor14.shtml#4272]])。
--初期化関数には、[[MIDPOINT:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/midpoint.shtml#1065868]](全ノードを入力ベクトル範囲の中央値で初期化)を指定しています([[参考:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/selfo13a.shtml]])。
---入力ベクトルに依存しない初期化関数として、[[INITZERO:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/initzero.shtml]](ゼロベクトル初期化)、[[RANDS:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/rands.shtml]](ランダム値初期化)があります。
---サンプル:[[これ:http://shower.human.waseda.ac.jp/~m-kouki/matlab/testSOM_init.m]]を実行してみてください。
~
~
--ここまでと同様の処理(ネットワークオブジェクトを宣言 ~ SOMのプロパティ設定)は、関数NEWSOMを使って、 
#geshi(matlab){{
 net = newsom(iprange,[5 4],'gridtop','boxdist', 0.9, 1000, 0.02, 1);
}}
とすることでも実現できます。

-これでネットワークの初期設定が終わりました。
--構造体netの中身は、 
 net
とすることで確認できます。 
--初期状態の(初期化された)SOMの各ノードの重み値は、
#geshi(matlab){{
 wts = net.IW{1,1}
}}
とすることで確認できます。関数 MIDPOINT によって入力範囲の中央に初期化されているため、全て同じ値(0.5×13)です。
--初期状態のSOMの、入力ベクトル空間内における各ノードの位置は、
#geshi(matlab){{
 plotsom(net.iw{1,1},net.layers{1}.distances)
}}
とすることで確認できます。赤い点が初期ニューロンのベクトル(全て同じ値)です。
---実行結果は以下のようになります。~
&ref(http://shower.human.waseda.ac.jp/~m-kouki/matlab/SOM_1.JPG);~

---「Warning - PLOTSOM only shows first three dimensions.」というエラーが出ています。入力ベクトルは実際には13次元の特徴量を持っているけれど、ここでは3次元までしか表示できません、ということです。
---2次元の入力ベクトルによるSOMの学習例については、[[これ:http://shower.human.waseda.ac.jp/~m-kouki/matlab/Ndist.m]]を入力ベクトルにして試してみてください。

-続いて、学習(重みとバイアスの更新)を行います。
--逐次型の適応学習(ADAPT)か、バッチ型の訓練学習(TRAIN)か、どちらかを選択して実行します。 
-~
#geshi(matlab){{
 %ネットワークを逐次型で学習させる(適応)
 net.adaptParam.passes = 100;    %TRAINSのパラメータ(連続列全体を通る100個のパス)
 %入力ベクトルをセル配列に格納
 Psize = size(P);                %入力ベクトルのデータ数(=総ステップ数)
 Pcell = cell(1,Psize(2));       %入力ベクトルのデータ数個のセルを持ったセル配列
 for count = 1:1:Psize(2)
     Pcell{count} = P(:,count);  %各セルに各入力データを代入
 end
 % 適応を開始
 net = adapt(net,Pcell);
}}

--関数[[ADAPT:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/adapt.shtml#498775]]は、[[逐次型学習:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/model212.shtml#32551]](入力ベクトルの各行(ステップ)に対して、毎回重みを更新)を行います。
---SOMの適応関数として「[[TRAINS:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/trains.shtml#971820]]」を指定しているため、関数のパラメータを指定する必要があります(指定しなければ、デフォルトのままで実行)。
---ADAPT 学習の入力ベクトルは、[[セル配列:http://dl.cybernet.co.jp/matlab/support/manual/r14/toolbox/matlab/matlab_prog/?/matlab/support/manual/r14/toolbox/matlab/matlab_prog/ch_daa37.shtml#matlab_cell_arrays]]である必要があります。
---適応関数 trains の各ステップの処理のところでプロット命令を追記すると、リアルタイムに適応学習の経過を観察できます。例えば '''[[trains_passsteps.m:http://shower.human.waseda.ac.jp/~m-kouki/pg/trains_passsteps.m]]'''(限定公開)
-~
#geshi(matlab){{
 %ネットワークをバッチ型で学習させる(訓練)
 % 訓練関数TRAINRのパラメータを指定
 net.trainParam.epochs = 100;  %最大エポック数(データセットを100エポック繰り返し訓練)
 net.trainParam.goal = 0;      %パフォーマンスゴール
 net.trainParam.show = 25;     %表示する間のエポック数(表示なしの場合NaN)
 net.trainParam.time = inf;    %訓練のための最大時間(秒)
 % 訓練を開始
 net = train(net,P);
}}

--関数[[TRAIN:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/train.shtml#670973]]は、[[バッチ型学習:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/model213.shtml#31790]](入力ベクトル全体に対して、最後にまとめて重みを更新)を行います。
---SOMの訓練関数として「[[TRAINR:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/trainr.shtml#968748]]」を指定しているため、関数のパラメータを指定する必要があります(指定しなければ、デフォルトのままで実行)。
---訓練学習の経過を詳しく見たい場合は、訓練関数に '''[[trainr_epochsteps.m:http://shower.human.waseda.ac.jp/~m-kouki/pg/trainr_epochsteps.m]]''' を使用してください(限定公開)。

-学習済みネットワークに入力ベクトルを与え、出力結果をシミュレートします。
#geshi(matlab){{
 %ネットワークのシミュレーション
 a = sim(net,P);         %入力ベクトルを与えて、出力ベクトルをクラスのインデックスに変換する
 a = vec2ind(a)          % 0 もしくは 1 のスパースなベクトルを、連続値のベクトルに変換
}}

-出力される値は、「各入力ベクトルに対する競合学習の結果、SOMの何番のノードが勝利したか」です。そのため、ここでもう一度SOMの構造を確認して、何番のノードがどの位置にあるのかを確認します。
#geshi(matlab){{
 %出力層の構造を確認
 outputFields = [];
 for count = 1:1:(opSizeX * opSizeY)
     outputFields = [outputFields count];
 end
 %各入力ベクトルをSOMのマップ型に並べ替えて出力
 outputFields = reshape( outputFields, opSizeX, opSizeY )
 %SOMのマップ型のセル配列を作成する
 somcell = cell(opSizeX, opSizeY);
 %入力ベクトルのラベルと出力ベクトルを合わせて表示する
 for count = 1 : 1 : length(Plabel)
     [Yco,Xco] = find(outputFields == a(count));
     disp(strcat('入力 「', Plabel(count,:), '」 のカテゴリは ', int2str(a(count)),...
         ' → 座標に換算すると (X,Y) = (', int2str(Xco), ', ', int2str(Yco), ')'));
     somcell{Yco,Xco} = strcat(somcell{Yco,Xco}, ' ', Plabel(count,:));
 end
 somcell
}}

--実行結果は以下のようになります(結果は実行のたびに変わります)。~
&ref(http://shower.human.waseda.ac.jp/~m-kouki/matlab/SOM_2.png);~
---「a」は学習を終えたSOMに、入力ベクトルを順番に示したとき、それぞれ何番のノードと対応付けられたか(入力ベクトルに対する競合学習の結果、どのノードが「勝利」したか)を示します。
---「outputFields」が今回作成したSOMの構造です。四角形のBOXDIST構造で、数字は各ノードの番号を示します。
---最後に、入力ベクトルのラベルに従って入力ベクトルの出力ノードとその座標を計算して、学習結果を求めています。
--似た特徴量をもった入力値(動物)は、SOM上でお互いに近い位置に配置されていることが分かります。

-

-他の方法で、学習済みのSOMを評価してみます。
--学習を終えたSOMの各ノードの重み値は、
#geshi(matlab){{
 wts = net.IW{1,1}
}}
とすることで確認できます。

--初期状態のSOMの、入力ベクトル空間内における各ノードの位置は、
#geshi(matlab){{
 plotsom(net.iw{1,1},net.layers{1}.distances)
}}
とすることで確認できます。

---入力ベクトルが4次元以上の特徴量をもつ場合、[[PLOTSOM:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/plotsom.shtml#1031936]]による表示はあまり効果的ではないですが、3次元以下の場合、入力ベクトル空間内の密度の高いところ(多くの入力値が存在するところ)に多くのノードが近づく様子が確認できます。

-&color(red){新しい入力値を提示するには};
--例えば、以下のような新しい入力値が、学習済み SOM ではどのクラスに分類されるかを確認します。~
&ref(http://shower.human.waseda.ac.jp/~m-kouki/matlab/animal_tuika.png);~
#geshi(matlab){{
 P2 = [
     0 1 0 1 0 0 0 0 0 1 0 0 0
     1 0 0 1 0 1 0 0 1 0 0 0 1
 ]
 P2label = strvcat('ヒト','ペンギン')
 
 %連結
 P = [P P2']
 Plabel = [Plabel ; P2label]
 
 %評価
 a = sim(net,P);
 a = vec2ind(a);
 outputFields = [];
 for count = 1:1:(opSizeX * opSizeY)
     outputFields = [outputFields count];
 end
 outputFields = reshape( outputFields, opSizeX, opSizeY )
 somcell = cell(opSizeX, opSizeY);
 for count = 1 : 1 : length(Plabel)
     [Yco,Xco] = find(outputFields == a(count));
     disp(strcat('入力 「', Plabel(count,:), '」 のカテゴリは ', int2str(a(count)),...
         ' → 座標に換算すると (X,Y) = (', int2str(Xco), ', ', int2str(Yco), ')'));
     somcell{Yco,Xco} = strcat(somcell{Yco,Xco}, ' ', Plabel(count,:));
 end
 somcell
}}

-&color(red){SOMマップベースのクラスタリング結果表示法};

-&color(red){各ノードがどの入力値にもっとも強く対応付けられているかを知るには};
--各ノードの重み値 net.IW{1,1} を確認します。

***基本SOMの予備的考察 [#p3d40add]
-入力ベクトルに相関がない(重複する値がない)場合の学習結果
--SOM vs K-means法([[testSOMandKMEANS.m:http://shower.human.waseda.ac.jp/~m-kouki/pg_public/testSOMandKMEANS.m]])ではうまくクラスタリングできました。
--6つの入力ベクトルを6クラスに分類([[testSomInputVector.m:http://shower.human.waseda.ac.jp/~m-kouki/pg_public/testSomInputVector.m]])では、うまくいかないようです?&color(red){→原因要調査!};
-カテゴリ数の評価
--[[寺島幹彦, 白谷文行, 山本公明,"自己組織化特徴マップ上のデータ密度ヒストグラムを用いた教師なしクラスタ分類法," 電子情報通信学会論文誌, Vol.J79-D-II, No.7, pp.1280-1290, 1996.:http://ci.nii.ac.jp/naid/110003227574]]
---[[demo_somOnkyoColor.m:http://shower.human.waseda.ac.jp/~m-kouki/pg_public/demo_somOnkyoColor.m]]
---'''[[入力の数のみによる判定( L = V ):http://shower.human.waseda.ac.jp/~m-kouki/pg/testSOM_histCategory1.m]]'''(限定公開)
---'''[[入力の数+重みによる判定( L = V / dM ):http://shower.human.waseda.ac.jp/~m-kouki/pg/testSOM_histCategory2.m]]'''(限定公開)
---両端のノードの、(すなわち存在しない)隣接ノードの重みをどうとるかによって、両端が山になるか、谷になるかが変わる。
-[[参考 前処理と後処理:http://dl.cybernet.co.jp/matlab/support/manual/r13/toolbox/nnet/?/matlab/support/manual/r13/toolbox/nnet/backpr19.shtml#5218]]

***多層SOM - SOM-SOM型 [#pddca1e0]
-&color(red){以下は編集途中のコンテンツです。};
-[[参考 2006.05.30 抑制を加えた単層SOMと多層SOMの考察:http://bryan.human.waseda.ac.jp/~m.kouki/blog/pdf/20060530.pdf]]~
~
-ここで作成するSOMは、1層目、2層目ともに5×4の二次元マップとします。
--第 1 層 : 中間層、 第 2 層 : 出力層 です。

-入力ベクトルの宣言までは、単層と同じです。
#geshi(matlab){{
 P = [
     1 0 0 1 0 0 0 0 1 0 0 1 0
     1 0 0 1 0 0 0 0 1 0 0 0 0
     1 0 0 1 0 0 0 0 1 0 0 1 1
     1 0 0 1 0 0 0 0 1 0 0 1 1
     1 0 0 1 0 0 0 0 1 1 0 1 0
     1 0 0 1 0 0 0 0 1 1 0 1 0
     0 1 0 1 0 0 0 0 1 1 0 0 0
     0 1 0 0 1 1 0 0 0 0 1 0 0
     0 1 0 0 1 1 0 0 0 0 1 0 0
     0 1 0 0 1 1 0 1 0 1 1 0 0
     1 0 0 0 1 1 0 0 0 1 0 0 0
     0 0 1 0 1 1 0 0 0 1 1 0 0
     0 0 1 0 1 1 0 1 0 1 1 0 0
     0 0 1 0 1 1 1 1 0 0 1 0 0
     0 0 1 0 1 1 1 1 0 0 1 0 0
     0 0 1 0 1 1 1 0 0 0 0 0 0
 ]
 Plabel = strvcat('ハト','メンドリ','アヒル','ガチョウ','フクロウ','タカ','ワシ','キツネ',...
    'イヌ','オオカミ','ネコ','トラ','ライオン','ウマ','シマウマ','ウシ')
 P = P';                                     %行と列を転置
 
 % 入力ベクトルの行数(Y 軸のサイズ、特徴量の数)、列数(X 軸のサイズ、データセットの数)を調べる
 [ipSizeY,ipSizeX] = size(P)
 % 入力層の要素の範囲を生成
 iprange = [min(P') ; max(P')]';             %[最小値 最大値]を特徴量の数だけ行方向に連結
 
-続いて、新規のネットワークオブジェクトを生成して、SOMの固有プロパティを宣言します。 
 opSizeX = 5;
 opSizeY = 4;
 s = [opSizeX*opSizeY opSizeX*opSizeY];      %[第1層のニューロン数 第2層のニューロン数]
 Nl = length(s);                             %ニューロンの数 s の列数(層の数)
 
 % ネットワークアーキテクチャ
 net = network(1, Nl);
 % 引数 : 入力層の数 = 1、層の数 = Nl(2) (その他の設定は以下で個別に指定)
 for countLayer = 1:1:Nl
     net.biasConnect(countLayer) = 0;        %バイアスの有無(層 1 も層 2 もバイアスをもたない)
 end
 net.inputConnect(1,1) = 1;                  %層 1 のみ入力層からの重みをもつ
 for countLayer = 2:1:Nl
 % 各層の結合の有無( countLayer 番目の層から countLayer-1 番目の層へ結合する)
     net.layerConnect(countLayer,countLayer-1) = 1;
 end
 net.outputConnect(Nl) = 1;                  % Nl 番目の層(出力層)はネットワーク出力をもつ
 
 net.inputs{1}.range = iprange;              % 1 番目の入力層の要素の範囲を指定
 
 for countLayer = 1:1:Nl
    % countLayer 番目の層の物理的な次元(この説明では、各層は全て同じサイズ)
    net.layers{countLayer}.dimensions = [opSizeX opSizeY];
    %層の次元から countLayer 番目の層のニューロンの位置を求めるトポロジー関数
    net.layers{countLayer}.topologyFcn = 'gridtop';
    %※ ニューロンの位置から 1 番目の層(中間層)のニューロン間の距離を求める距離関数
    net.layers{countLayer}.distanceFcn = 'boxdist';
 end
 
 % 入力層から 1 番目の層(中間層)への重み関数
 net.inputWeights{1,1}.weightFcn = 'negdist';
 
 % 各層(出力層)のニューロン数、出力計算用の伝達関数
 for countLayer = 1:1:Nl
   net.layers{countLayer}.size = s(countLayer);     % countLayer 番目の層のニューロン数
    net.layers{countLayer}.transferFcn = 'compet';   % countLayer 番目の層の伝達関数
 end
 
 % 各層の重み行列学習関数
 %  1番目の入力層から 1 番目の層(中間層)への重み行列学習関数
 net.inputWeights{1,1}.learnFcn = 'learnsom';       % LEARNSOM(SOM重み学習関数) 
 % LEARNSOMのパラメータを指定
 net.inputWeights{1,1}.learnParam.order_lr = 0.9;     %順序付けフェイズの学習比
 net.inputWeights{1,1}.learnParam.order_steps = 1000; %順序付けフェイズのステップ数
 net.inputWeights{1,1}.learnParam.tune_lr = 0.02;     %調整フェイズの学習比
 net.inputWeights{1,1}.learnParam.tune_nd = 1;        %調整フェイズの近傍距離
 %  層どうしの重み行列学習関数、バイアス更新用関数
 for countLayer = 2:1:Nl
     net.layerWeights{countLayer,1}.learnFcn = 'learnsom';      % LEARNSOM 
     net.layerWeights{countLayer,1}.learnParam.order_lr = 0.9;     %順序付けフェイズの学習比
     net.layerWeights{countLayer,1}.learnParam.order_steps = 1000; %順序付けフェイズのステップ数
     net.layerWeights{countLayer,1}.learnParam.tune_lr = 0.02;     %調整フェイズの学習比
     net.layerWeights{countLayer,1}.learnParam.tune_nd = 1;        %調整フェイズの近傍距離
 end
 
 % 訓練関数
 net.trainFcn = 'trainr'
 
 % 初期化関数
 net.initFcn = 'initlay';                    %INITLAY(層ごと)
 %  層から層への重み行列初期化関数
 for countLayer = 2:1:Nl
     net.layerWeights{countLayer,countLayer-1}.initFcn = 'midpoint';
 end
 %  入力層から層 1 への重み行列初期化関数
 net.inputWeights{1,1}.initFcn = 'midpoint'; %MIDPOINT(中間点重み初期化)
 % 初期化を実行
 net = init(net);
}}

-これでネットワークの初期設定が終わりました。 
--初期状態の(初期化された)SOMの各ノードの重み値は、 
#geshi(matlab){{
 wtsL1 = net.IW{1,1}       % 1 番目の入力層から 1 番目の層への重み
 wtsL2 = net.LW{2,1}       % 1 番目の層から 2 番目の層への重み
}}
とすることで確認できます。関数 MIDPOINT によって入力範囲の中央に初期化されているため、全て同じ値(0.5×13)です。 

-続いて、学習(重みとバイアスの更新)を行います。 
#geshi(matlab){{
 %ネットワークをバッチ型で学習させる(訓練)
 net.trainParam.epochs = 100;  %入力ベクトルを100エポック繰り返し入力
 net.trainParam.goal = 0;      %パフォーマンスゴール
 net.trainParam.show = 25;     %表示する間のエポック数(表示なしの場合NaN)
 net.trainParam.time = inf;    %訓練のための最大時間(秒)
 net = train(net,P);           %学習開始(入力ベクトルに対して重みとバイアスを調整)
}}

-学習済みネットワークに入力ベクトルを与え、出力結果をシミュレートします。 
#geshi(matlab){{
 % ネットワークのシミュレーション
 P                       %入力ベクトル
 % 出力層の構造を確認
 outputFields = [];
 for count = 1:1:(opSizeX * opSizeY)
     outputFields = [outputFields count];
 end
 % 各入力ベクトルをSOMのマップ型に並べ替えて出力
 outputFields = reshape( outputFields, opSizeX, opSizeY )
 
 % ネットワークのシミュレーション 1層目
 %  入力層 ⇔ 1 層目 と同じ構造、重みの単層ネットワークを作成して、それに対してsimを実行します。
 %     もっとうまいやり方があるかも?
 simnet1 = network(1, 1);
 simnet1.biasConnect(1) = 0;
 simnet1.inputConnect(1,1) = 1;
 simnet1.outputConnect(1) = 1;
 simnet1.inputs{1}.range = iprange;
 simnet1.layers{1}.dimensions = [opSizeX opSizeY];
 simnet1.layers{1}.topologyFcn = 'gridtop';
 simnet1.layers{1}.distanceFcn = 'boxdist';
 simnet1.inputWeights{1,1}.weightFcn = 'negdist';
 simnet1.layers{1}.transferFcn = 'compet';
 simnet1.inputWeights{1,1}.learnFcn = 'learnsom';
 simnet1.inputWeights{1,1}.learnParam.order_lr = 0.9;
 simnet1.inputWeights{1,1}.learnParam.order_steps = 1000;
 simnet1.inputWeights{1,1}.learnParam.tune_lr = 0.02;
 simnet1.inputWeights{1,1}.learnParam.tune_nd = 1;
 simnet1.initFcn = 'initlay';
 simnet1.inputWeights{1,1}.initFcn = 'midpoint';
 simnet1 = init(simnet1);           %初期化を実行
 % 学習済みネットワークの 入力層 ⇔ 1 層目 の重みをコピー
 simnet1.IW{1,1} = net.IW{1,1};
 wtsL1 = simnet1.IW{1,1}            % 1 番目の入力層から 1 番目の層への重み
 aL1 = sim(simnet1,P);              %ネットワークの出力
 aL1 = vec2ind(aL1)                 % 0 もしくは 1 のスパースなベクトルを、連続値のベクトルに変換
 Pcell = cell(opSizeX, opSizeY);
 for count = 1 : 1 : length(Plabel)
     [Yco,Xco] = find(outputFields == aL1(count));
     disp(strcat('入力 「', Plabel(count,:), '」 のカテゴリは ', int2str(aL1(count)),...
         ' → 座標に換算すると (X,Y) = (', int2str(Xco), ', ', int2str(Yco), ')'));
     Pcell{Yco,Xco} = strcat(Pcell{Yco,Xco}, ' ', Plabel(count,:));
 end
 Pcell
 
 % ネットワークのシミュレーション 出力層
 %  こちらは、普通に学習済みネットワークをシミュレーションします。
 if Nl > 1
    wtsL2 = net.LW{2,1}             % 1 番目の層から 2 番目の層への重み
     aL2 = sim(net,P);               %ネットワークの出力
     aL2 = vec2ind(aL2);             % 0 もしくは 1 のスパースなベクトルを、連続値のベクトルに変換
     %入力ベクトルのラベルと出力ベクトルを合わせて表示する
     Pcell = cell(opSizeX, opSizeY);
     for count = 1 : 1 : length(Plabel)
         [Yco,Xco] = find(outputFields == aL2(count));
         disp(strcat('入力 「', Plabel(count,:), '」 のカテゴリは ', int2str(aL2(count)),...
             ' → 座標に換算すると (X,Y) = (', int2str(Xco), ', ', int2str(Yco), ')'));
         Pcell{Yco,Xco} = strcat(Pcell{Yco,Xco}, ' ', Plabel(count,:));
     end
     Pcell
 end
}}

-デモプログラム
--[[test2LaySOM3.m:http://shower.human.waseda.ac.jp/~m-kouki/pg_public/test2LaySOM3.m]]

***多層SOM - SOM-教師あり型 [#v0844101]

***Tips [#u39cd1ca]
-アーキテクチャ
--[[関数 learnsom:http://www.mathworks.com/access/helpdesk_archive_ja_JP/r13/help/toolbox/nnet/index.html?/access/helpdesk_archive_ja_JP/r13/help/toolbox/nnet/learnsom.html#500592]]
--[[Neural Network Toolbox および SOM のアーキテクチャに関する報告:http://shower.human.waseda.ac.jp/~m-kouki/blog/pdf/20061114.pdf]]
 → 逐次型学習とバッチ型学習(エポックとステップ) の違い
 → 競合学習関数 COMPET のアルゴリズム(自作したSimnetとの違いは?)
 → 自己組織化マップの重み付け変更関数 LEARNSOM のアルゴリズム
 → 離散入力値/連続入力値、入力値の相関と学習結果に関して