相比于bp神经网络算法,som相对来说比较容易理解。自组织神经网络,是一种用于聚类的神经网络算法,从名字便可以看出,这是一种无监督式的算法,意味着,它不需要任何训练样本,便可以直接对输入样本根据其特征 分类,将具有相似特征的划分为一类。
1 算法结构
som算法是由两层网络组成,输入层与输出层(也叫作竞争层),大致示意图如下:

2 示例
下面我会给出一个例子来讲解som算法的原理。
现在我有8个输入样本,每个输入样本由两个特征值组成(x,y),表示在二维坐标系(横为x,纵为y)上如下图所示:

要求使用som算法将上图中的输入节点划分为两类。
解:如图所示:凭肉眼观察,8个输入样本很明显已经分为了粉红与淡蓝两类,但题意要求使用som算法来搞。所以思路如下:
1 2 3 4 5 6 7 8 9 10 11 12 | <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趋于稳定(阈值(步长)很小)。 |
没有太高深的数学计算,但这就是som算法的思路,我做了一个简单的动画来描述上面的计算过程。
两个黑色的节点即为输出节点,是随机生成的,随着算法的运行,你会发现,两个节点分别移动向两个类别之中(这里步长为0.15)。
结合着我贴出的python源代码,更加方便去理解这种算法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #-*- coding:utf-8 -*- # som 实例算法 by 自由爸爸 import random import math input_layer = [[39,281],[18,307],[24,242],[54,333],[322,35],[352,17],[278,22],[382,48]] # 输入节点 category = 2 class Som_simple_zybb(): def __init__(self,category): self.input_layer = input_layer # 输入样本 self.output_layer = [] # 输出数据 self.step_alpha = 0.5 # 步长 初始化为0.5 self.step_alpha_del_rate = 0.95 # 步长衰变率 self.category = category # 类别个数 self.output_layer_length = len(self.input_layer[0]) # 输出节点个数 2 self.d = [0.0] * 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(0,400)) # som 算法的主要逻辑 # 计算某个输入样本 与 所有的输出节点之间的距离,存储于 self.d 之中 def calc_distance(self,a_input ): self.d = [0.0] * 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]),2) # 就不开根号了 # 计算一个列表中的最小值 ,并将最小值的索引返回 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 = 0 while self.step_alpha >= 0.0001: # 这样子会执行167代 self.train() generate +=1 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() |
解答完毕!
相信分析完这篇教程,som算法就没什么难的了。
这篇教程搞懂之后,努力方向应为som的完善算法sofm(自组织特征映射神经网络),这种算法相比于som算法,有两处不同:
1 . 步长的衰变方式。
2 . 每次输出层的获胜节点确定之后,不仅仅该获胜节点要调整自身特征值,获胜节点周围相近的节点也要做相应的调整,调整幅度的大小要视距离获胜节点的远近。
留给课下研究好了。

本文介绍了一种用于聚类的无监督神经网络算法——自组织神经网络(SOM),并通过实例演示了如何通过SOM算法对输入样本进行分类。文章还提供了一个Python实现的例子。
1551





