天天看點

【轉】自組織神經網絡算法-SOMSelf Organizing Maps : 一種基于神經網絡的聚類算法

入職後的第一個工作任務是使用python實作一篇論文中的提到的算法,該算法使用了LVQ神經網絡,全稱為“學習矢量量化神經網絡”,想要了解這個模型必須先對SOM有一個簡單的了解。找到一篇講解很清晰的文章,收藏以供學習。

Self Organizing Maps : 一種基于神經網絡的聚類算法

自組織神經網絡,是一種用于

聚類

的神經網絡算法,從名字便可以看出,這是一種

無監督式

的算法,意味着它不需要任何訓練樣本,便可以直接對輸入樣本根據其特征分類,将具有

相似特征

的劃分為一類。

som算法是由兩層網絡組成,輸入層與輸出層(也叫作競争層),大緻示意圖如下:

【轉】自組織神經網絡算法-SOMSelf Organizing Maps : 一種基于神經網絡的聚類算法

算法原理

一個例子來講解som算法的原理。現在我有8個輸入樣本,每個輸入樣本由兩個特征值組成(x,y),要求将圖中的輸入節點劃分為兩類,表示在二維坐标系(橫為x,縱為y)如下圖所示:

【轉】自組織神經網絡算法-SOMSelf Organizing Maps : 一種基于神經網絡的聚類算法

憑肉眼觀察,8個輸入樣本很明顯已經分為了粉紅與淡藍兩類,使用som算法來做思路如下:

<1>.因為輸入樣本的特征為2(分别是x與y坐标值),共有8個輸入樣本,是以輸入層的節點數為8(注意此處節點數不像BP神經網絡那樣将每個樣本的特征數目作為輸入樣本的個數,這裡将每個輸入樣本作為一個輸入節點會更加容易了解)。
<2>.因為最終要劃分為兩類,是以需要定義兩個輸出樣本,是以輸出節點為2,且兩個輸出節點的特征數為2(x,y)。
<3>.根據以上規則随機初始化兩個輸出節點W。
<4>.for 每一個輸入節點 INPUT{
        for 每一個輸出節點W{
           計算目前輸入節點i與輸出節點w之間的歐式距離;
        }
        找到離目前輸入節點i最近(歐式距離最小)的那個輸出節點w作為獲勝節點;
        調整w的特征值,使該w的特征值趨近于目前的輸入節點(有個門檻值(步長)控制幅度);
    }
    衰減門檻值(步長);
<5>. 循環執行步數<4>,直到輸出節點W趨于穩定(門檻值(步長)很小)。
           

原文中有一個gif動圖可以很清晰地了解算法執行過程,詳情見文末連結。

源代碼

#-*- coding:utf-8 -*-
import random
import math
input_layer = [[,],[,],[,],[,],[,],[,],[,],[,]] # 輸入節點
category = 

class Som_simple_zybb():
    def __init__(self,category):
        self.input_layer = input_layer # 輸入樣本
        self.output_layer = [] # 輸出資料
        self.step_alpha =  # 步長 初始化為0.5
        self.step_alpha_del_rate =  # 步長衰變率
        self.category = category # 類别個數
        self.output_layer_length = len(self.input_layer[]) # 輸出節點個數 2
        self.d = [] * self.category

    # 初始化 output_layer
    def initial_output_layer(self):
        for i in range(self.category):
            self.output_layer.append([])
            for _ in range(self.output_layer_length):
                self.output_layer[i].append(random.randint(,))

    # som 算法的主要邏輯
    # 計算某個輸入樣本 與 所有的輸出節點之間的距離,存儲于 self.d 之中
    def calc_distance(self,a_input ):
        self.d = [] * self.category
        for i in range(self.category):
            w = self.output_layer[i]
            # self.d[i] =
            for j in range(len(a_input)):
                self.d[i] += math.pow((a_input[j] - w[j]),) # 就不開根号了

    # 計算一個清單中的最小值 ,并将最小值的索引傳回
    def get_min(self,a_list):
        min_index = a_list.index(min(a_list))
        return min_index

    # 将輸出節點朝着目前的節點逼近
    def move(self,a_input,min_output_index):
        for i in range(len(self.output_layer[min_output_index])):
            self.output_layer[min_output_index][i] = self.output_layer[min_output_index][i] + self.step_alpha * ( a_input[i] - self.output_layer[min_output_index][i] )

    # som 邏輯 (一次循環)
    def train(self):
        for a_input in self.input_layer:
            self.calc_distance(a_input)
            min_output_index = self.get_min(self.d)
            self.move(a_input,min_output_index)

    # 循環執行som_train 直到穩定
    def som_looper(self):
        generate = 
        while self.step_alpha >= : # 這樣子會執行167代
            self.train()
            generate +=
            print("代數:{0} 此時步長:{1} 輸出節點:{2}".format(generate,self.step_alpha,self.output_layer))
            self.step_alpha *= self.step_alpha_del_rate # 步長衰減

if __name__ == '__main__':
    som_zybb = Som_simple_zybb(category)
    som_zybb.initial_output_layer()
    som_zybb.som_looper()
           

轉載自 http://www.ziyoubaba.com/archives/606

繼續閱讀