【转】学习向量量化神经网络-LVQ

入职后的第一个工作任务是使用python实现一篇论文中的提到的算法,该算法使用了LVQ神经网络,全称为“学习矢量量化神经网络”。找到一篇讲解很清晰的文章,收藏以供学习。

Learning Vector Quantization : 一种基于神经网络的聚类算法

LVQ网络是一种有监督学习的自组织竞争网络,他与SOM的主要区别在于“有监督”这仨字。具体描述的话,可以总结为两点:

<1>所以对于输入的数据,需要给出其种类标签label。
<2>找到距离当前输入节点(i)最近的输出层节点(o)之后,som直接调节o的特征使之趋近于i,而lvq则首先比较i与o的种类标签label是否是相同的,如果相同,则代表二者属于相同的种类,并调节o的特征使之趋近于i;反之,则调节o的特征使之远离于i。

LVQ的层级结构大致示意图如下:
示意图

算法原理

现在我有8个输入样本,每个输入样本由两个特征值组成(x,y),要求将图中的输入节点划分为两类,表示在二维坐标系(横为x,纵为y)如下图所示:
这里写图片描述

凭肉眼观察,8个输入样本很明显已经分为了粉红与淡蓝两类,使用LVQ算法来做思路如下:

<1>.因为输入样本的特征为2(分别是x与y坐标值),共有8个输入样本,所以输入层的节点数为8。
<2>.因为最终要划分为两类,所以需要定义两个输出样本,所以输出节点为2,且两个输出节点的特征数为2(x,y)。
<3>.根据以上规则随机初始化两个输出节点W。
<4>.for 每一个输入节点 INPUT{
        for 每一个输出节点W{
           计算当前输入节点i与输出节点w之间的欧式距离;
        }
        找到离当前输入节点i最近(欧式距离最小)的那个输出节点w作为获胜节点;
        调整w的特征值,比较i与w的种类标签label是否是相同的,如果相同,则代表二者属于相同的种类,并调节w的特征使之趋近于i;反之,则调节w的特征使之远离于i。
    }
    衰减阈值(步长);
<5>. 循环执行步数<4>,直到输出节点W趋于稳定(阈值(步长)很小)。

原文中有一个gif动图可以很清晰地了解算法执行过程,详情见文末链接。

源代码

#-*- coding:utf-8 -*-
import random
import math

input_layer = [[39, 281], [18, 307], [24, 242], [54, 333], [322, 35], [352, 17], [278, 22], [382, 48]]  # 输入节点
category_list = [0,0,0,0,1,1,1,1]   # 对应着输入节点的类别(两类:0/1)
category = 2

class LVQ_sample_zybb():
    def __init__(self, category):
        self.input_layer = input_layer  # 输入样本
        self.output_layer = []  # 输出数据
        self.output_layer_cate = [] # 存储着输出样本的种类
        self.step_alpha = 0.5  # 步长 初始化为0.5
        self.step_alpha_del_rate = 0.95  # 步长衰变率
        self.category = category  # 类别个数
        self.category_list = category_list
        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_cate.append(i)  # 主要分为两类 0/1 。初始化输出类别列表,分别对应着两个输出节点
            self.output_layer.append([])
            for _ in range(self.output_layer_length):
                self.output_layer[i].append(random.randint(0, 400))

    # lvq 算法的主要逻辑
    # 计算某个输入样本 与 所有的输出节点之间的距离,存储于 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_index ,a_input, min_output_index):
        # 作为有监督式学习 这里体现了与som算法不同之处(也是唯一的不同之处)
        if self.category_list[a_input_index] == self.output_layer_cate[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])
        else:
            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])

    # lvq 主要逻辑 (一次循环)
    def train(self):
        # for a_input in self.input_layer:
        for i in range(len(self.input_layer)):
            a_input = self.input_layer[i]
            self.calc_distance(a_input)
            min_output_index = self.get_min(self.d)
            self.move(i,a_input, min_output_index)

    # 循环执行 train 直到稳定
    def lvq_looper(self):
        generate = 0
        while self.step_alpha >= 0.0001:  # 这样子会执行167代
            print("代数:{0} 此时步长:{1} 输出节点:{2} 对应的类别为:{3}".format(generate, self.step_alpha, self.output_layer,self.output_layer_cate))
            self.train()
            generate += 1
            # print("代数:{0} 此时步长:{1} 输出节点:{2} 对应的类别为:{3}".format(generate, self.step_alpha, self.output_layer,self.output_layer_cate))
            self.step_alpha *= self.step_alpha_del_rate  # 步长衰减

if __name__ == '__main__':
    lvq_zybb = LVQ_sample_zybb(category)
    lvq_zybb.initial_output_layer()
    lvq_zybb.lvq_looper()

转载自 http://www.ziyoubaba.com/archives/701


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值