Matlab代码实现SOM(自组织映射)算法

som可用于聚类,图像分割等,由于论文需要matlab实现了som。

%som实现
%2016-11-12
%by wangbaojia
%  som原理及参数说明
% 1.竞争:匹配最佳神经元---------->计算每个样本和初始神经网络的距离,距离最近神经元作为获胜神经元
%
% 2.合作:在权值更新过程中,不仅获胜神经元的权
%值向量得到更新,而且其近邻神经元的权值向量也按照某个“近邻函数”进行更新。这样在开
%始时移动量很大,权值向量大致地可按它们的最终位置来排序;
%获胜神经元决定兴奋神经元的拓扑邻域的空间位置,从而提供了相邻神经元合作的基础
%   拓扑邻域:规则多边形一般都可以作为邻域形状,常用的主要有正方形或六边形,正方形更为普遍
%
%权重向量的调整就发生在获胜神经元的邻域内。在训练的刚开始阶段,这个邻域比较大,
%随着训练的进行,这个邻域开始不断减小
%
% 3.自适应:权值更新过程
% 算法:
% 1.初始化
%    1)迭代次数:时间步长iter
%    2)输出结点权值向量初始值,向量各元素可选区间(0,1)上的随机值,这里选择正方形邻域
%    3)学习率初始值
%    4)邻域半径的设置应尽量包含较多的邻神经元,整个输出平面的一半
% 2.求竞争获胜神经元;欧拉距离函数求解
% 3.权值更新:
%        获胜节点和邻域范围内神经元集合的m个节点更新权值,j=1:m;    
%            wj(t+1)=wj(t)+learnfun(t)*neighborfun(t)*(x-wj);
% 4.更新学习率,更新邻域函数 
%        neighborfun(t)=neighbor0*exp(-dij/t1);   t1=iter/log(neighbor0)
%         learnfun(t)=learn0*exp(-t/t2);     t2=iter
% 5.当特征映射不再发生明显变化时或达到最大网络训练次数时退出,否则转入第2步

%载入数据,data数据每一行为一个用空格区分的多维数据样本
tic;
%样本数据的位置
file_path='C:\Users\Administrator\Desktop\testclustering\test1\';
path=strcat(file_path,'data.txt');
%path=strcat(file_path,'data_path.txt');
data=load(path);
[data_row,data_clown]=size(data);

%自组织映射网络m*n
m=5;
n=5;
%神经元节点总数som_sum
som_sum=m*n;
%权值初始化,随机初始化
w = rand(som_sum, data_clown);
%初始化学习率
learn0 = 0.6;
learn_rate = learn0;
%学习率参数
learn_para=1000;
%设置迭代次数
iter =500;
%神经元位置
[I,J] = ind2sub([m, n], 1:som_sum);
%邻域初始化 
neighbor0 =2;
neighbor_redius = neighbor0;
%邻域参数
neighbor_para = 1000/log(neighbor0);
 
%迭代次数
for t=1:iter 
    %  样本点遍历
    for j=1:data_row  
        %获取样本点值
        data_x = data(j,:); 
        %找到获胜神经元
        [win_row, win_som_index]=min(dist(data_x,w'));  
        %获胜神经元的拓扑位置
        [win_som_row,win_som_cloumn] =  ind2sub([m, n],win_som_index);
        win_som=[win_som_row,win_som_cloumn];
        %计算其他神经元和获胜神经元的距离,邻域函数
        %distance_som = sum(( ([I( : ), J( : )] - repmat(win_som, som_sum,1)) .^2) ,2);
        distance_som = exp( sum(( ([I( : ), J( : )] - repmat(win_som, som_sum,1)) .^2) ,2)/(-2*neighbor_redius*neighbor_redius)) ;
        %权值更新
        for i = 1:som_sum
           % if distance_som(i)<neighbor_redius*neighbor_redius 
            w(i,:) = w(i,:) + learn_rate.*distance_som(i).*( data_x - w(i,:));
        end
    end
 
    %更新学习率
    learn_rate = learn0 * exp(-t/learn_para);   
    %更新邻域半径
    neighbor_redius = neighbor0*exp(-t/neighbor_para);  
end
%data数据在神经元的映射
%神经元数组som_num存储图像编号
som_num=cell(1,size(w,1));
for i=1:size(w,1)
    som_num{1,i}=[];
end
%每个神经元节点对应的data样本编号
for num=1:data_row
    [som_row,clown]= min(sum(( (w - repmat(data(num,:), som_sum,1)) .^2) ,2));
    som_num{1,clown}= [som_num{1,clown},num];    
end

%存储神经元数组,.mat格式
path1=strcat(file_path,'som_num.mat');
save(path1,'som_num');
toc;

1)针对一些问题这里统一说明一下,data中的数据没有标签的类别属性,data.txt文本数据为每一行为一个用空格区分的多维数据样本,读者的数据中如果有类别标签可取出单独用一个数组存放 ,若想要对聚类效果进行评价,如使用NMI值进行评估时,再和聚类输出结果进行比较计算,代码如下贴出,否则以上计算中不涉及类别标签
2)以上代码只是som的收敛过程,还需要进一步的聚类收敛,如使用K-means算法对som聚类中心进行聚类达到最后的聚类结果
3)各种聚类算法各有适用范围,som并不具有普适性,总体上som使用的并不多,在图像分割上较为常见,大家掌握思想就好

function score = nmi(true_labels, cluster_labels)
%NMI Compute normalized mutual information (NMI) using the true and cluster
%   labels and return the value in 'score'.
%
%   Input    : true_labels    : N-by-1 vector containing true labels
%              cluster_labels : N-by-1 vector containing cluster labels
%
%   Output   : score          : NMI value
%
%   Reference: Shi Zhong, 2003.
%              http://www.cse.fau.edu/~zhong/software/textclust.zip

% Compute the confusion matrix 'cmat', where
%   col index is for true label (CAT),
%   row index is for cluster label (CLS).
n = length(true_labels);
cat = spconvert([(1:n)' true_labels ones(n,1)]);
cls = spconvert([(1:n)' cluster_labels ones(n,1)]);
cls = cls';
cmat = full(cls * cat);

n_i = sum(cmat, 1); % Total number of data for each true label (CAT), n_i
n_j = sum(cmat, 2); % Total number of data for each cluster label (CLS), n_j

% Calculate n*n_ij / n_i*n_j
[row, col] = size(cmat);
product = repmat(n_i, [row, 1]) .* repmat(n_j, [1, col]);
index = find(product > 0);
n = sum(cmat(:));
product(index) = (n*cmat(index)) ./ product(index);
% Sum up n_ij*log()
index = find(product > 0);
product(index) = log(product(index));
product = cmat .* product;
score = sum(product(:));
% Divide by sqrt( sum(n_i*log(n_i/n)) * sum(n_j*log(n_j/n)) )
index = find(n_i > 0);
n_i(index) = n_i(index) .* log(n_i(index)/n);
index = find(n_j > 0);
n_j(index) = n_j(index) .* log(n_j(index)/n);

denominator = sqrt(sum(n_i) * sum(n_j));
%denominator = -(sum(n_i) +sum(n_j))./2;

% Check if the denominator is zero
if denominator == 0
  score = 0;
else
  score = score / denominator;
end

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值