#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 のアルゴリズム
→ 離散入力値/連続入力値、入力値の相関と学習結果に関して