自己組織化マップのコードを書いてみた

自己組織化マップを簡単に勉強してみたので,
ついでにMATLABでプログラムを書いてみた.

アルゴリズムはwikipediaとかを参考に書いてみた.

RGBのデータを適当に用意して,そのデータに対してSOMを試してみた.

以下,ソースと実行結果.

ソース

% setting sample data
clear;
nData = 1000;
data_x = 0.6*rand(nData, 3)+ 0.4;

% setting node
width = 10;
height = 10;
nNode = height * width;
node_x = rand(nNode, 3);


% % loop
nLoop = 100;
for iLoop = 1:nLoop
    sigma = exp(-0.01*iLoop);
    alpha = sigma;
    
    for iData = 1:nData
        dist = node_x - repmat(data_x(iData,:), nNode, 1);
        dist = sum(dist.^2, 2);
        [~, min_node_i] = min(dist);
        near_node_is = getNearNode(min_node_i, height, width);
        min_data_x = data_x(iData,:);
        
        for inn = 1:numel(near_node_is)
            near_node_i = near_node_is(inn);
            near_node_x = node_x(near_node_i,:);
            
            coff = alpha * exp(-dist(near_node_i) / sigma);
            node_x(near_node_i,:) = near_node_x + coff * (min_data_x - near_node_x);
        end
        
    end
    
    figure(1);
    image(reshape(node_x, height, width, 3));
    drawnow;
end
% メッシュ上でノードiの近傍のノードを返す
function nis = getNearNode(i, h, w)
y = mod(i-1, h)+1;
x = ceil(i / h);

foo = @(x,y) (x-1)*h + y;

nis = [i];

% plane
if y+1 <= h, nis = [nis, foo(x,y+1)]; end
if y-1 >= 1, nis = [nis, foo(x,y-1)]; end
if x+1 <= w, nis = [nis, foo(x+1,y)]; end
if x-1 >= 1, nis = [nis, foo(x-1,y)]; end

% taurus
% nis = [nis, foo(x,mod(y,h)+1)];
% nis = [nis, foo(x,mod(y-1,h)+1)];
% nis = [nis, foo(mod(x,w)+1,y)];
% nis = [nis, foo(mod(x-1,w)+1,y)];

end

実行結果

メッシュのノードごとに出力してみた.
データは色なので,フルカラーとRGBごとに出力してみた.

フルカラー/赤/緑/青
f:id:nosyan:20110811181448p:image:left
f:id:nosyan:20110811181447p:image:left
f:id:nosyan:20110811181446p:image:left
f:id:nosyan:20110811181445p:image:left

それっぽくクラスタリングできてますねー.
なかなか,面白い結果.

SOMの説明には大体,ニューラルネットワークがふんたらという説明があるけど,あれじゃ全然分からないと思うんだ.

おいら,SOMの感覚は2次元多様体状のメッシュを多次元のデータにフィッティングして,データを近似する感じ.

まぁ正しいかどうかは分かんないけど.