目次
(2) サンプル点と重みベクトル間のトポロジカル距離を計算します。
1. SOM の概要
SOM (Self Organizing Map) 自己組織化マップ ネットワーク。競合ニューラル ネットワークとも呼ばれます。高次元データを単純な構造と相互関係を持つ低次元空間にマッピングすることで表示でき、データの視覚化、クラスタリング、分類などの機能を実現します。
SOM ネットワークは他のニューラル ネットワークとは異なり、他のニューラル ネットワークと比較して Kmeans クラスタリング アルゴリズム、つまり K 平均法クラスタリング アルゴリズムに近いです。
その構造を以下の図に示します。
この図から、出力層の各ノードは D 個の重みエッジを介して入力ノードに接続されており (つまり、出力層の各ノードは D 次元の重み Wij で表されます)、各ノード間の関係がわかります。出力層のノードは距離に応じて一定のつながりがあります。
2. SOMトレーニングプロセス
(1) 初期化
初期重みベクトルのランダムな値を選択します
(2) サンプリング(サンプル点の抽出)
入力データからサンプル点を入力トレーニング ベクトル サンプルとして抽出します。
(3) 競争
重みベクトルの場合、ニューロンはそれぞれの判別関数値を計算し、これが競合の基礎となります。最小の判別関数値を持つ特定のニューロンが勝者と宣言されます。(判別関数は、入力トレーニング ベクトル サンプルと重みベクトルの間の二乗ユークリッド距離として定義できます)
Vernacular: 各ニューロンと 2 番目のステップで選択したトレーニング サンプル ポイントの間のトポロジカルな距離を計算し、最も近い距離が勝者の重みベクトル ポイント (勝者) になります。
(4) 協力と適応(重量値の更新)
神経生物学的研究では、興奮性ニューロンのグループ内での横方向の相互作用が発見されました。ニューロンが活性化されると、最も近くにあるニューロンは、遠くにあるニューロンよりも興奮する傾向があります。そして、距離とともに減衰するトポロジカルな近傍が存在します。
前のステップで勝ったニューロンが重み値を決定する権利を獲得します。勝利したニューロンが重みを更新するだけでなく、その近隣のニューロンも、勝ったニューロンほどではありませんが、重みを更新されます。
最も近いウェイト ベクトル ノードがサンプル点まで一定距離移動し、隣接するノードも一定距離移動することがわかります。
(5) 繰り返し
ステップ 2 に戻り、すべての入力データ ポイントが一致するまで繰り返します。
3. Python コードの実装
(1) 初期化
def __init__(self, X, output, iteration, batch_size):
"""
:param X: 形状是N*D, 输入样本有N个,每个D维
:param output: (n,m)一个元组,为输出层的形状是一个n*m的二维矩阵
:param iteration:迭代次数
:param batch_size:每次迭代时的样本数量
初始化一个权值矩阵,形状为D*(n*m),即有n*m权值向量。权值由numpy随机函数生成。
"""
self.X = X
self.output = output
self.iteration = iteration
self.batch_size = batch_size
self.W = np.random.rand(X.shape[1], output[0] * output[1])
print(self.W.shape)
(2) サンプル点と重みベクトル間のトポロジカル距離を計算します。
def GetN(self, t):
"""
:param t:时间t, 这里用迭代次数来表示时间
:return: 返回一个整数,表示拓扑距离,时间越大,拓扑邻域越小
"""
a = min(self.output)
return int(a - float(a) * t / self.iteration)
def Geteta(self, t, n):
"""
:param t: 时间t, 这里用迭代次数来表示时间
:param n: 拓扑距离
:return: 返回学习率,
"""
return np.power(np.e, -n) / (t + 2)
(3) 競争
def train(self):
"""
train_Y:训练样本与形状为batch_size*(n*m)
winner:一个一维向量,batch_size个获胜神经元的下标
:return:返回值是调整后的W
"""
count = 0
while self.iteration > count:
train_X = self.X[np.random.choice(self.X.shape[0], self.batch_size)]
normal_W(self.W)
normal_X(train_X)
train_Y = train_X.dot(self.W)
winner = np.argmax(train_Y, axis=1).tolist()
self.updata_W(train_X, count, winner)
count += 1
return self.W
def train_result(self):
normal_X(self.X)
train_Y = self.X.dot(self.W)
winner = np.argmax(train_Y, axis=1).tolist()
print(winner)
return winner
(4) 重みを更新する
def updata_W(self, X, t, winner):
N = self.GetN(t)
for x, i in enumerate(winner):
to_update = self.getneighbor(i[0], N)
for j in range(N + 1):
e = self.Geteta(t, j)
for w in to_update[j]:
self.W[:, w] = np.add(self.W[:, w], e * (X[x, :] - self.W[:, w]))
def getneighbor(self, index, N):
"""
:param index:获胜神经元的下标
:param N: 邻域半径
:return ans: 返回一个集合列表,分别是不同邻域半径内需要更新的神经元坐标
"""
a, b = self.output
length = a * b
def distence(index1, index2):
i1_a, i1_b = index1 // a, index1 % b
i2_a, i2_b = index2 // a, index2 % b
return np.abs(i1_a - i2_a), np.abs(i1_b - i2_b)
ans = [set() for i in range(N + 1)]
for i in range(length):
dist_a, dist_b = distence(i, index)
if dist_a <= N and dist_b <= N: ans[max(dist_a, dist_b)].add(i)
return ans