自己組織化マップで色マップ画像作成

[やること]

自己組織化マップ(Self-Organizing Maps)で、RGBで表現された色データを、教師なし学習して、色マップを作成します。

 

[自己組織化マップの説明]

教師なし学習の手法です。

入力データに関して、近いデータを近くに配置するマップを作成します。

参考資料[1]がわかりやすいです

  

[結果1]

黒、緑、黄、赤、紫、白、水、青の8色を学習させた結果です。

青と水、赤と紫、など、近い色が近くに配置されています。

f:id:wada0421514:20200329114954p:plain

 

[結果2]

以下の12色相環の12色を学習させた結果です。

12色相環を再現できています。

f:id:wada0421514:20200329115153p:plain

f:id:wada0421514:20200329115156p:plain

 

[プログラムについて]

参考資料[2]をかなり参考にしました

import numpy as np
import cv2

class SOM:
def __init__(self, n_side, n_learn=1000, c=0.5):
#n_side:マップのサイズ,n_learn:学習回数,c:更新率
self.n_side = n_side
self.n_learn = n_learn
self.c = c
self.n_weight = self.n_side * self.n_side

def fit(self, input_vector):

input_vector = np.array(input_vector)
n_input = len(input_vector)
n_vector = input_vector.shape[1]

# pointsにはそれぞれの重みの(x,y)座標が入っている(範囲は[0,1))
points = np.array([[i // self.n_side, i % self.n_side] for i in range(self.n_weight)])
points = points / (1.0 * self.n_side)

# 重みベクトルの初期化
self.weight = np.zeros((self.n_weight, n_vector))

# ランダムなインデックス
random_index = np.arange(n_input)
np.random.shuffle(random_index)

for t in range(self.n_learn):

# ランダムに一つ抽出
vec = input_vector[random_index[t % n_input]]

# 勝ちニューロン決定
winner_index = np.argmin(np.linalg.norm(diff, axis=1))
winner_point = points[winner_index]

# 近傍関数の計算
alpha = 1.0 - float(t) / self.n_learn#α=1-t/T:学習回数に応じて単調に減少
delta_point = points - winner_point
dist = np.linalg.norm(delta_point, axis=1)#勝ちニューロンとの距離
h = self.c * alpha * np.exp(- (dist / alpha) ** 2)

# 重みを更新
diff = vec - self.weight# 入力ベクトルと重みの差
self.weight += np.atleast_2d(h).T * diff


if __name__ == "__main__":

    #8色のRGB
    input_vector=[[255,255,255],[255,255,0],[255,0,255],[0,255,255],
                  [0,0,255],[0,255,0],[255,0,0],[0,0,0]]

    #12色相環のRGB
    color_wheel=[[255, 0, 0],[255, 127, 0],[255, 255, 0],[127, 255, 0],
                 [0, 255, 0],[0, 255, 127],[0, 255, 255],[0, 127, 255],
                 [0, 0, 255],[127, 0, 255],[255, 0, 255],[255, 0, 127]]

    # SOMクラスの作成・学習
    n_side = 500 # 一辺の長さ
    som = SOM(n_side, n_learn=1000,c=0.75)
    som.fit(color_wheel)

    # 重みベクトルの取得
    output_imgs = som.weight

    # 重みベクトルを並べて、画像作成
    output_imgs = output_imgs.reshape(n_side, n_side, 3)
    tile = np.zeros((n_side, n_side,3))
    for x in range(n_side):
    for y in range(n_side):
    tile[(x):(x+1), (y):(y+1)] = output_imgs[x, y]

    # 画像の保存
    print(tile)
    cv2.imwrite("tile.png", tile)

  

[参考資料]

[1]自己組織化特徴マップ(SOM)

http://www.sist.ac.jp/~kanakubo/research/neuro/selforganizingmap.html

[2]MNISTの自己組織化マップ(SOM)を作った[Python]-もりとーにのブログ

https://tony-mooori.blogspot.com/2016/01/mnistpython.html