python实现SOM算法


Posted in Python onFebruary 23, 2018

算法简介

SOM网络是一种竞争学习型的无监督神经网络,将高维空间中相似的样本点映射到网络输出层中的邻近神经元。

训练过程简述:在接收到训练样本后,每个输出层神经元会计算该样本与自身携带的权向量之间的距离,距离最近的神经元成为竞争获胜者,称为最佳匹配单元。然后最佳匹配单元及其邻近的神经元的权向量将被调整,以使得这些权向量与当前输入样本的距离缩小。这个过程不断迭代,直至收敛。

  • 网络结构:输入层和输出层(或竞争层),如下图所示。
  • 输入层:假设一个输入样本为X=[x1,x2,x3,…,xn],是一个n维向量,则输入层神经元个数为n个。
  • 输出层(竞争层):通常输出层的神经元以矩阵方式排列在二维空间中,每个神经元都有一个权值向量。
  • 假设输出层有m个神经元,则有m个权值向量,Wi = [wi1,wi2,....,win], 1<=i<=m。

python实现SOM算法

算法流程:

1. 初始化:权值使用较小的随机值进行初始化,并对输入向量和权值做归一化处理
          X' = X/||X||
          ω'i= ωi/||ωi||, 1<=i<=m
          ||X||和||ωi||分别为输入的样本向量和权值向量的欧几里得范数。

2.将样本输入网络:样本与权值向量做点积,点积值最大的输出神经元赢得竞争,
(或者计算样本与权值向量的欧几里得距离,距离最小的神经元赢得竞争)记为获胜神经元。

3.更新权值:对获胜的神经元拓扑邻域内的神经元进行更新,并对学习后的权值重新归一化。
        ω(t+1)= ω(t)+ η(t,n) * (x-ω(t))
        η(t,n):η为学习率是关于训练时间t和与获胜神经元的拓扑距离n的函数。
        η(t,n)=η(t)e^(-n)
        η(t)的几种函数图像如下图所示。

4.更新学习速率η及拓扑邻域N,N随时间增大距离变小,如下图所示。

5.判断是否收敛。如果学习率η<=ηmin或达到预设的迭代次数,结束算法。

python实现SOM算法python实现SOM算法

python代码实现SOM

import numpy as np
import pylab as pl

class SOM(object):
  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权值向量,每个D维
    """
    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)

  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)

  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



  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

def normal_X(X):
  """
  :param X:二维矩阵,N*D,N个D维的数据
  :return: 将X归一化的结果
  """
  N, D = X.shape
  for i in range(N):
    temp = np.sum(np.multiply(X[i], X[i]))
    X[i] /= np.sqrt(temp)
  return X
def normal_W(W):
  """
  :param W:二维矩阵,D*(n*m),D个n*m维的数据
  :return: 将W归一化的结果
  """
  for i in range(W.shape[1]):
    temp = np.sum(np.multiply(W[:,i], W[:,i]))
    W[:, i] /= np.sqrt(temp)
  return W

#画图
def draw(C):
  colValue = ['r', 'y', 'g', 'b', 'c', 'k', 'm']
  for i in range(len(C)):
    coo_X = []  #x坐标列表
    coo_Y = []  #y坐标列表
    for j in range(len(C[i])):
      coo_X.append(C[i][j][0])
      coo_Y.append(C[i][j][1])
    pl.scatter(coo_X, coo_Y, marker='x', color=colValue[i%len(colValue)], label=i)

  pl.legend(loc='upper right')
  pl.show()

#数据集:每三个是一组分别是西瓜的编号,密度,含糖量
data = """
1,0.697,0.46,2,0.774,0.376,3,0.634,0.264,4,0.608,0.318,5,0.556,0.215,
6,0.403,0.237,7,0.481,0.149,8,0.437,0.211,9,0.666,0.091,10,0.243,0.267,
11,0.245,0.057,12,0.343,0.099,13,0.639,0.161,14,0.657,0.198,15,0.36,0.37,
16,0.593,0.042,17,0.719,0.103,18,0.359,0.188,19,0.339,0.241,20,0.282,0.257,
21,0.748,0.232,22,0.714,0.346,23,0.483,0.312,24,0.478,0.437,25,0.525,0.369,
26,0.751,0.489,27,0.532,0.472,28,0.473,0.376,29,0.725,0.445,30,0.446,0.459"""

a = data.split(',')
dataset = np.mat([[float(a[i]), float(a[i+1])] for i in range(1, len(a)-1, 3)])
dataset_old = dataset.copy()

som = SOM(dataset, (5, 5), 1, 30)
som.train()
res = som.train_result()
classify = {}
for i, win in enumerate(res):
  if not classify.get(win[0]):
    classify.setdefault(win[0], [i])
  else:
    classify[win[0]].append(i)
C = []#未归一化的数据分类结果
D = []#归一化的数据分类结果
for i in classify.values():
  C.append(dataset_old[i].tolist())
  D.append(dataset[i].tolist())
draw(C)
draw(D)

由于数据比较少,就直接用的训练集做测试了,运行结果图如下,分别是对未归一化的数据和归一化的数据进行的展示。

python实现SOM算法python实现SOM算法

参考内容:

1.《机器学习》周志华
2.自组织竞争神经网络SOM

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python3 中文乱码与默认编码格式设定方法
Oct 31 Python
python中数组和矩阵乘法及使用总结(推荐)
May 18 Python
pyqt5 删除layout中的所有widget方法
Jun 25 Python
详解有关PyCharm安装库失败的问题的解决方法
Feb 02 Python
Python读取VOC中的xml目标框实例
Mar 10 Python
python实现FTP循环上传文件
Mar 20 Python
scrapy爬虫:scrapy.FormRequest中formdata参数详解
Apr 30 Python
python如何写出表白程序
Jun 01 Python
python实现npy格式文件转换为txt文件操作
Jul 01 Python
基于python实现计算两组数据P值
Jul 10 Python
Python基于staticmethod装饰器标示静态方法
Oct 17 Python
python中numpy数组与list相互转换实例方法
Jan 29 Python
python实现k-means聚类算法
Feb 23 #Python
python写一个md5解密器示例
Feb 23 #Python
Python机器学习之K-Means聚类实现详解
Feb 22 #Python
python实现远程通过网络邮件控制计算机重启或关机
Feb 22 #Python
python实现微信发送邮件关闭电脑功能
Feb 22 #Python
python使用itchat实现手机控制电脑
Feb 22 #Python
Python实现利用163邮箱远程关电脑脚本
Feb 22 #Python
You might like
用定制的PHP应用程序来获取Web服务器的状态信息
2006/10/09 PHP
php字符串截取的简单方法
2013/07/04 PHP
WordPress中访客登陆实现邮件提醒的PHP脚本实例分享
2015/12/14 PHP
php倒计时出现-0情况的解决方法
2016/07/28 PHP
php获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
js 函数的执行环境和作用域链的深入解析
2009/11/01 Javascript
IE、FF浏览器下修改标签透明度
2014/01/28 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
2014/08/18 Javascript
用JavaScript实现使用鼠标画线的示例代码
2014/08/19 Javascript
在JavaScript中访问字符串的子串
2015/07/07 Javascript
Javascript简单改变表单元素背景的方法
2015/07/15 Javascript
js实现横向伸展开的二级导航菜单代码
2015/08/28 Javascript
基于HTML模板和JSON数据的JavaScript交互(移动端)
2016/04/06 Javascript
Web 开发中Ajax的Session 超时处理方法
2017/01/19 Javascript
ES6新特性之变量和字符串用法示例
2017/04/01 Javascript
浅谈js使用in和hasOwnProperty获取对象属性的区别
2017/04/27 Javascript
ReactNative踩坑之配置调试端口的解决方法
2017/07/28 Javascript
构建大型 Vue.js 项目的10条建议(小结)
2019/11/14 Javascript
javascript中可能用得到的全部的排序算法
2020/03/05 Javascript
vue实现购物车案例
2020/05/30 Javascript
[35:39]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第二场 11.22
2020/11/24 DOTA
[49:30]DOTA2-DPC中国联赛正赛 Dragon vs Dynasty BO3 第二场 3月4日
2021/03/11 DOTA
python遍历 truple list dictionary的几种方法总结
2016/09/11 Python
Python实现的简单读写csv文件操作示例
2018/07/12 Python
python散点图实例之随机漫步
2018/08/27 Python
Python闭包装饰器使用方法汇总
2020/06/29 Python
Pytorch - TORCH.NN.INIT 参数初始化的操作
2021/02/27 Python
澳大利亚一站式数码相机商店:CameraPro
2020/03/09 全球购物
意大利包包和行李箱销售网站:Bagaglio.it
2021/03/02 全球购物
护理学毕业生求职信
2013/11/14 职场文书
计算机专业大学生的自我评价
2013/11/14 职场文书
上学迟到的检讨书
2014/01/11 职场文书
中学生爱国演讲稿
2014/09/05 职场文书
个人批评与自我批评总结
2014/10/17 职场文书
预备党员转正党小组意见
2015/06/01 职场文书
保护环境建议书作文300字
2015/09/14 职场文书