-->

自己組織化マップ






自己組織化マップ(Self-Organizing Map SOM) は、 Teuvo Kohonen によって考案された高次元データを主に2 次元平面上や3 次元球面上に非線形写像するデータ解析手法の一つである. SOM のアルゴリズムは、似た性質を有するデータがマップ上で近くに集まるように構築されている. 自己組織化マップ (Self-Organizing Map: SOM) はフィンランドの研究者,T. Kohonenの発明したニューラルネットの一種である.SOM は教師なし学習を行う位相保存写像(topology preserving mapping) の一種である.高次元の観測データセットに対し,SOM はデータ分布の位相的構造を保存しつつ低次元空間へ写像する.特に 2 次元空間へ写像する場合はデータ分布が地図 (topographic map) のように可視化される.この地図をデータマイニングに用いるのが典型的な SOM の利用法である.
歴史的に見れば,SOM は大脳視覚野における機能地図の自己組織化モデルに由来する.
大脳皮質ではさまざまな機能を持つ神経細胞が規則性を持って配置されており,発生・成長の過程で適切な配線が自己組織的に行われる.これをデータマイニングなど工学的に利用したのが Kohonen の SOMの出発点である.したがって神経系における自己組織的機能分化というサイエンス的側面と,データマイニングなどの工学的側面の2つの顔を SOM は持つ.
SOM のアルゴリズムはさまざまな解釈が可能である.ニューラルネットワークの視点では (1) Winner-Take-All による競合,(2) 近傍関数による協調的学習分配,(3) Hebb 則に基づくシナプス荷重の更新という3つのプロセスの繰り返し計算と解釈できる.一方,機械学習的視点では広義の EM アルゴリズムと見ることができ,E ステップと M ステップのループを繰り返す.
SOM はさまざまなニューラルネットや機械学習の手法と関係している.次元削減による可視化という点では主成分分析 (Principal Component Analysis: PCA) や多次元尺度法 (Multidimensional Scaling: MDS) などが関連する.多様体による高次元データ分布の近似という点では多様体学習 (minifold learning) の一種でもある.一方で SOM はベクトル量子化 (Vector Quantization: VQ) に位相の概念を組み込んだもの,あるいはデータ分布をグラフ構造でモデル化したものとも解釈できる.また SOM は潜在変数モデル (latent variable model) でもある.中でも生成位相写像 (Generative Topographic Mapping: GTM)およびガウス過程潜在変数モデル (Gaussian Process Latent Variable Model: GPLVM)はベイズ的機械学習の観点で再構築した SOM と見ることができる.

神経研究は、人間の脳でおこなわれている情報処理の仕組みを、認知心理学的に、生理学および解剖学を基礎にした脳神経科学の分野で、さらには数理科学的に脳の仕組みを解明してみようというところから出発している.
神経の構造および機能に関しては20世紀はじめにはすでに細かく調べられていた.
1943年、形式神経の形ではじめてMcCulloとPittsがモデル化した.



2. 参考
下村政嗣・山口智彦(編) 2009 自己組織化ハンドブック エヌ・ティー・エス
古川 徹生 http://www.brain.kyutech.ac.jp/~furukawa/data/SOMtext.pdf






<div id="id_container_main"></div>

<style type="text/css">
body {
    background-color: #005214;
    font: 16px sans-serif;
    color: rgb(255, 241, 202);
}

button.minibtn {
    font: 16px sans-serif;
    color: rgb(255, 241, 202);
 
    border: 1px solid rgb(255, 241, 202);
    background-color: #005214;
    margin: 4px; 
    padding-bottom: 2px;
}

button.minibtn:active {
    position: relative;
    top: 1px;
    left: 1px;
    background-color: #80c080;
}
</style>


<script>
// 初期情報
var basePx = 9;
var zoom = 22;
var dotsData = [basePx * basePx];
var matrixLineWidth = 0;
var matrixLineColor = 'rgba(192, 192, 192, 1)';
var learnCnt = 0;
var learnMax = 5000;
var intId = null;
var initdotsData = [basePx * basePx];
var inputValueType = 0;    // 0:random, 1:rgb, 2:from initial colors

// 共通関数
var rnd = function(max){return Math.floor(Math.random() * (max-110)+110);};
var createDivWithId = function(arg){
    var o = document.createElement('div');
    o.id = 'id_' + arg;
    return o;
};
var rgba = function(r, g, b){return 'rgba(' + r + ', ' + g + ', ' + b + ', 1)';};
var rndColor = function(){return rgba(rnd(130), rnd(256), rnd(180));};

// R・G・B配列分割
var rgbVal = function(str){
  var tmp = str.match(/[0-9]+/g);
  return {r:tmp[0], g:tmp[1], b:tmp[2]};//rgbVal;
};

// get rgb average values from string
var avrgVal = function(str){
    var tmpVal = rgbVal(str);
    // 赤の自乗、緑の自乗、青の自乗の合計の自乗根
    var tmpAbs = Math.sqrt(Math.pow(tmpVal.r, 2) + Math.pow(tmpVal.g, 2) + Math.pow(tmpVal.b, 2));
    return {r:(tmpVal.r / tmpAbs), g:(tmpVal.g / tmpAbs), b:(tmpVal.b / tmpAbs)};
};


// 開始位置
Ini();

//funcions
function Ini(){
    // canvas init
    var fc = createDivWithId('canvas_parent');
    var cnvs = document.createElement('canvas');
    cnvs.id = 'id_somcanvas';
    cnvs.width = basePx * zoom;
    cnvs.height = basePx * zoom;
    cnvs.style.width = cnvs.width + 'px';
    cnvs.style.height = cnvs.width + 'px';
    cnvs.style.border = '1px solid gray';

    fc.appendChild(cnvs);

    /* button setup */
    var btn1 = document.createElement('button');
    btn1.textContent = '開始';
    btn1.className = 'minibtn';
    btn1.onclick = function(){
        learnStart(); // learn start
    };
    var btn2 = document.createElement('button');
    btn2.textContent = '停止';
    btn2.className = 'minibtn';
    btn2.onclick = function(){
        clearTimeout(intId); // stop
    };
    var btn3 = document.createElement('button');
    btn3.textContent = '初期化';
    btn3.className = 'minibtn';
    btn3.onclick = function(){
        clearTimeout(intId); // stop
        setupRndColor();  // reset
        learnCnt = 0;
        document.getElementById('id_cnvsdbg').innerHTML = '組織化数 ' + learnCnt + '/' + learnMax;
    };

    var bbx = createDivWithId('cnvscontrol');
    bbx.appendChild(btn1);
    bbx.appendChild(btn2);
    bbx.appendChild(btn3);

    fc.appendChild(bbx);

    var cd = createDivWithId('cnvsdbg');
    fc.appendChild(cd);
    document.getElementById('id_container_main').appendChild(fc);

    setupRndColor();

}

// 無作為色ぬりつぶし
function setupRndColor(){
    var cnvs = document.getElementById('id_somcanvas');
    var ctx = cnvs.getContext('2d');
    var i, j, color;
    var fillSize = zoom - matrixLineWidth;


    i=0;
    while(i < basePx){
        j=0;
        while(j < basePx){
            color = rndColor();
            ctx.fillStyle = color;
            dotsData[(i * basePx) + j] = color;
            initdotsData[(i * basePx) + j] = color;
            ctx.fillRect(j * zoom, i * zoom, fillSize, fillSize); //ぬりつぶし         
            j=j+1;
        }
        i=i+1;
    }
}

// 組織化開始
function learnStart(){
    intId = setTimeout(function(){
        if(learnCnt < learnMax){
          learnStartCore();
          learnCnt = learnCnt + 1;
        }else{
           clearTimeout(intId);
           learnCnt = 0;
        }
    }, 0);
}

// 組織化主処理
function learnStartCore(){
    var inputColor = ''; //RGB
    if(inputValueType === 0){  /* input value type 1 */
        inputColor = rndColor();
    }else if(inputValueType === 1){ /* input value type 2 */
        var arg = rnd(3);
        var r = 0.1, g = 0.1, b = 1;
            if(arg === 0){
                r = 1; g = 0.1; b = 0.1;
            }else if(arg === 1){
                r = 0.1; g = 1; b = 0.1;
            }
        inputColor = rgba(Math.floor(rnd(130) * r), Math.floor(rnd(256) * g), Math.floor(rnd(180) * b));
    }else{       /* input value type 3 */
        inputColor = initdotsData[rnd(initdotsData.length)];
    }

    var icv = rgbVal(inputColor); //R・G・B配列分割
    var i, j;
    var max = 0, p = 0, q = 0;
    var node;
    var tmpValA, tmpValB;
    var prod;
 
    // 最類似決定
    i = 0;
    while(i < basePx){
        j = 0;
        while(j < basePx){
            node = dotsData[(i * basePx) + j];
            // calcurate rgb * rgb (vector prod)
            tmpValA = avrgVal(inputColor);
            tmpValB = avrgVal(node);
            prod = (tmpValA.r * tmpValB.r) + (tmpValA.g * tmpValB.g) + (tmpValA.b * tmpValB.b);
            if(prod > max){
                max = prod;
                p = i;
                q = j;
            }
            j = j + 1;
        }
        i = i + 1;
    }

    // 修正範囲決定
    var sigmaPow = 0.4;
    var updateArea = [];
    var ofsi, ofsj;
    var dist;
    var gaussianCoe;
 
    i = 0;
    while(i < 5){
        j = 0;
        while(j < 5){
            ofsi = p + i - 2;
            ofsj = q + j - 2;
            if(!((ofsi < 0) || (ofsj < 0) || (ofsi >= basePx) || (ofsj >= basePx))){
                //var dist = (Math.sqrt(Math.pow((ofsi - p), 2) + Math.pow((ofsj - q), 2)) / Math.sqrt(8));
                dist = Math.sqrt(Math.pow((ofsi - p), 2) + Math.pow((ofsj - q), 2));
                gaussianCoe = (1 / Math.sqrt(Math.PI * 2 * sigmaPow)) * Math.exp(0 - (Math.pow(dist, 2) / (2 * sigmaPow)));
                updateArea.push({x:ofsj, y:ofsi, coe:gaussianCoe});
            }
            j = j + 1;
        }
        i = i + 1;
    }

    // learn(update color)
    var cnvs = document.getElementById('id_somcanvas');
    var ctx = cnvs.getContext('2d');
    var fillSize = zoom - matrixLineWidth;
    var updateColor = '';
    var coeff;
    var tcv = '';

    // Neighborhood function
    var gaussian = ((1 / Math.sqrt(Math.PI * 2)) * Math.exp(0 - (Math.pow(learnCnt / learnMax, 2) / 2))) / 0.4;

    i = 0;
    while (i < updateArea.length){
        coeff = updateArea[i].coe * gaussian;
        tcv = rgbVal(dotsData[(updateArea[i].y * basePx) + updateArea[i].x]);

        // calc new color
        updateColor = rgba(Math.floor((icv.r * coeff) + (tcv.r * (1 - coeff))),  Math.floor((icv.g * coeff) + (tcv.g * (1 - coeff))),  Math.floor((icv.b * coeff) + (tcv.b * (1 - coeff))));

        dotsData[(updateArea[i].y * basePx) + updateArea[i].x] = updateColor;

        ctx.fillStyle = updateColor;
        ctx.fillRect(updateArea[i].x * zoom, updateArea[i].y * zoom, fillSize, fillSize);   
        i = i + 1;
    }

    document.getElementById('id_cnvsdbg').innerHTML = '組織化数 ' + (learnCnt + 1) + '/' + learnMax;

    learnStart();
}


</script>