SwiftyNote

主にSwiftな技術ブログ

【自己組織化写像:SOM】読ませる気のないアルゴリズムシリーズ【第二弾】

自己組織化写像とは

自律的に秩序を持つ構造を作り出す現象

ニューラルネットワークの一種で、教師なし学習が行える。応用としてNNはもちろん、クラスタリング手法としても用いられる。

色彩の分類に応用した例 http://www.sist.ac.jp/~kanakubo/research/neuro/neuro16.png

お、これは前回の記事のようにUIのグラデーション遷移などに応用できそうだ。早速やってみよう。

ソースコード

#include <iostream>
#include <cmath>

using namespace std;

typedef struct {
    int r;
    int g;
    int b;
}RGB;

typedef struct {
    int x;
    int y;
}POS;

const double PI = 3.1415926535;

//マップサイズ
const unsigned int SIZE = 20;

//試行回数
const unsigned int NUM = 10000;

//単調減少関数
double dec(int n){
    return 1.0 - (static_cast<double>(n) / NUM);
}

//結果
void disp(RGB col[SIZE][SIZE]){
    int max, sel;
    for(int i=0; i<SIZE; i++){
        for(int j=0; j<SIZE; j++){
            max=col[i][j].r;
            sel=0;
            if(max<=col[i][j].b && col[i][j].b>=col[i][j].g)sel=2;
            if(max<=col[i][j].g && col[i][j].b<=col[i][j].g)sel=1;
            switch(sel){
                case 0:
                    std::cout<<"● ";
                    break;
                case 1:
                    std::cout<<"× ";
                    break;
                case 2:
                    std::cout<<"□ ";
                    break;
            }
        }
        cout<<endl;
    }
}

//最大相関値の色の位置を取得
POS getMaxCor(RGB col[SIZE][SIZE],RGB value){
    POS pos;
    pos.x = pos.y=0;
    RGB min;
    min.r = min.g = min.b = INT_MAX;
    RGB tmp;
    for(int y=0; y<SIZE; y++){
        for(int x=0; x<SIZE; x++){
            tmp.r=abs(col[y][x].r - value.r);
            tmp.g=abs(col[y][x].g - value.g);
            tmp.b=abs(col[y][x].b - value.b);
            if(min.r+min.g+min.b >= tmp.r+tmp.g+tmp.b){
                min=tmp;
                pos.x=x;
                pos.y=y;
            }
        }
    }
    return pos;
}

//勝者ノードの値に近づける
void divideValue(RGB& col,RGB type){
    col.r = (col.r + type.r) / 2;
    col.g = (col.g + type.g) / 2;
    col.b = (col.b + type.b) / 2;
}

//8近傍関数
void fillMap(RGB col[SIZE][SIZE],RGB type,POS &index){
    int x,y;
    x=index.x;
    y=index.y;
    divideValue(col[y][x], type);
    if(y+1<SIZE && x+1<SIZE) divideValue(col[y+1][x+1], type);
    if(y-1>=0 && x-1>=0) divideValue(col[y-1][x-1], type);
    if(y+1<SIZE && x-1>=0) divideValue(col[y+1][x-1], type);
    if(y-1>=0 && x+1<SIZE) divideValue(col[y-1][x+1], type);
    if(y+1<SIZE) divideValue(col[y+1][x], type);
    if(y-1>=0) divideValue(col[y-1][x], type);
    if(x+1<SIZE) divideValue(col[y][x+1], type);
    if(x-1>=0) divideValue(col[y][x-1], type);
}

int main(int argc, const char * argv[]) {
    RGB rgb[SIZE][SIZE] = {0} , rtmp;
    POS p;
    //マップをランダムに初期化
    for(int y=0; y<SIZE; y++){
        for(int x=0;x<SIZE;x++){
            rgb[y][x].r=arc4random()%256;
            rgb[y][x].g=arc4random()%256;
            rgb[y][x].b=arc4random()%256;
        }
    }
    //自己組織化
    for(int i=0;i<NUM;i++){
        rtmp.r=(arc4random()%256);
        rtmp.g=(arc4random()%256);
        rtmp.b=(arc4random()%256);
        p=getMaxCor(rgb,rtmp);
        fillMap(rgb,rtmp,p);
    }
    //結果
    disp(rgb);
    return 0;
}

実行結果

[1]

× ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● □ □ □ 
× ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● □ □ □ 
× × ● ● ● ● ● ● ● ● ● ● ● ● ● ● □ □ □ □ 
× × ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● □ □ 
× × × × × × ● ● ● ● ● ● ● ● ● ● ● ● □ □ 
□ □ □ □ × × × ● ● ● ● ● ● ● ● ● ● ● ● □ 
□ □ □ □ × × × × ● ● ● ● ● ● ● ● ● ● ● ● 
□ □ □ × × × × × ● ● ● ● ● ● ● ● ● ● ● ● 
□ □ □ × × × × × ● ● ● ● ● ● ● ● ● ● ● ● 
□ □ × × × × × × × × ● ● ● ● ● ● ● ● □ □ 
● × × × × × × × × × × × × × ● ● ● □ □ □ 
● × × × × × × × × × × × × × ● ● □ □ □ □ 
× × × × × × × × × × × × × × □ □ □ □ □ □ 
× × × × × × × × × × × × × × □ □ □ □ □ □ 
× × × × × × × × × □ □ □ □ □ □ □ □ □ □ □ 
× × × × × × × × × □ □ □ □ □ □ □ □ □ □ □ 
× × × × × × × × × □ □ □ □ □ □ □ □ □ □ □ 
× × × × × × × × □ □ □ □ □ □ □ □ □ □ □ □ 
× × × × × × × × □ □ □ □ □ □ □ □ □ □ □ □ 
× × × × × × × × □ □ □ □ □ □ □ □ □ □ □ □ 

[2]

● ● ● ● ● ● × × × × × × × × ● ● ● □ □ × 
● ● ● ● ● ● × × × × × × × × ● ● ● □ □ × 
● ● ● ● ● ● × × × × × × × × ● ● ● □ □ × 
● ● ● ● ● ● × × × × × × × × × × × × × × 
● ● ● ● ● ● × × × × × × × × × × × × × × 
● ● ● ● ● ● × × × × × × × × × × × × × × 
● ● ● ● ● ● × × × × × × × × × × × □ × × 
● ● ● ● ● ● × ● ● ● × × × × × × × × □ □ 
● ● ● ● ● ● ● ● ● ● ● × × × × × × × × □ 
● ● ● ● ● ● ● ● ● ● □ □ □ × × × × × × × 
● ● ● ● ● ● ● ● ● ● □ □ □ □ □ □ □ × × × 
● ● ● ● ● ● ● ● ● ● □ □ □ □ □ □ □ □ □ □ 
● ● ● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ □ 
● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ 
● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ × 
● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ ● × × 
● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ ● ● ● 
● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ ● ● ● 
● □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ ● × × 
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ × × ×

[3]

● ● ● × × × × × □ □ □ □ □ □ □ □ □ □ □ □ 
● ● ● × × × × × □ □ □ □ □ □ □ □ □ □ □ □ 
● ● ● ● × × × × × × × × □ □ □ □ □ □ □ □ 
● ● ● ● × × × × × × × × × × □ □ □ □ □ □ 
● ● ● ● ● × × × × × × × × × × □ □ □ □ □ 
● ● ● ● ● × × × × × × × × × × × □ □ □ □ 
● ● ● ● ● × × × × × × × × × × × × × □ □ 
● ● ● ● ● × × × × × × × × × × × × × × × 
● ● ● ● ● ● × × × × × × × × × ● ● ● × × 
● ● ● ● ● ● × × × × × × × × × ● ● ● × × 
● ● ● ● ● ● × × × × × × × × ● ● ● ● ● ● 
● ● ● ● ● ● × × × × × × × × □ ● ● ● ● ● 
● ● ● ● ● ● ● ● × × × × × × □ □ □ □ □ ● 
● ● ● ● ● ● ● ● × × × × × □ □ □ □ □ □ □ 
● ● ● ● ● ● ● ● × × × × × □ □ □ □ □ □ □ 
● ● ● ● ● ● ● ● × × × × □ □ □ □ □ □ □ □ 
● ● ● ● ● ● ● ● ● × × × □ □ □ □ □ □ □ □ 
● ● ● ● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ 
● ● ● ● ● □ ● □ □ □ □ × □ □ □ □ □ □ □ □ 
● ● ● ● ● □ □ □ □ □ □ □ □ □ □ □ □ □ □ □

まずい、ある程度読めてしまう。 それは良いとして、なかなか面白い結果になった。今回は●×□の3種類でやってみたがN種類の色で自己組織化MAPを作ればグラデーションやBlurMaskに応用できそうだ。

自己組織化写像 - Wikipedia

自己組織化 - Wikipedia

rinov.hatenablog.com