相比于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 . 每次输出层的获胜节点确定之后,不仅仅该获胜节点要调整自身特征值,获胜节点周围相近的节点也要做相应的调整,调整幅度的大小要视距离获胜节点的远近。
留给课下研究好了。