竞争网络-算法原理与自实现
SOM神经网络
SOM-代码重写(单样本训练)
作者 : 老饼 日期 : 2022-06-09 04:42:02 更新 : 2022-06-29 01:25:56
本站原创文章,转载请说明来自《老饼讲解-BP神经网络》bp.bbbdata.com



本文是笔者细扒matlab2009b神经网络工具箱newsom的源码,

在源码的基础上去除冗余代码,重现的简版newsom代码,代码与newsom的结果完全一致。
通过本代码的学习,可以完全细节的了解SOM单样本训练的实现逻辑。





  01. 代码结构说明  


代码主要包含了三个函数:   testSomNet      trainSomNet      predictSomNet  


testSomNet:  测试用例主函数,直接运行时就是执行该函数。


1、数据生成:随机生成一组训练数据,
2、用自写的函数训练一个SOM网络,与预测结果。
3、使用工具箱训练一个SOM网络。
4、比较自写函数与工具箱训练结果是否一致(权重、训练误差的比较)


trainSomNet:网络训练主函数,用于训练一个SOM神经网络。


单样本训练方式,训练一个SOM神经网络


predictSomNet:用训练好的网络进行预测。


传入需要预测的X,与网络的权重矩阵,即可得到预测结果。






02. 代码运行结果解说


运行代码后,得到预测结果与对比结果,如下:




 

从中可以看到,自写代码与工具箱的逻辑一致。






03. 具体代码


matlab2009b亲测已跑通:



%------------测试DEMO函数------------------
function testSomNet()
%本代码来自bp.bbbdata.com
%本代码模仿matlab神经网络工具箱的newsom神经网络,用于训练《SOM神经网络》,
%本代码扒自matlab2009b,使用的是旧版newsom单样本训练算法,在新版matlab中不再使用。
%代码主旨用于教学,供大家学习理解newsom神经网络原理
% ---------数据生成与参数预设-------------
% 数据生成
rand('seed',70);
X = [rand(1,400)*2; rand(1,400)];    % 生成样本
test_x = [0.5 0.6;0.5 0.6];                  % 测试样本
epochs = 10;                         % 训练步数
dimensions = [4 3];                  % 输出节点拓扑维度

%---------调用自写函数进行训练--------------
rand('seed',70);
w = trainSomNet(X,dimensions,epochs);
py = find(predictSomNet(w,test_x))

% -----调用工具箱,与工具箱的结果比较------
% 调用工具箱进行训练
rand('seed',70);
Xr = [min(X,[],2),max(X,[],2)];
net = newsom(Xr,dimensions);
net.trainParam.epochs = epochs;
net = train(net,X);

% 工具箱的结果
pyByTool = find(sim(net,test_x))
w_tools  = net.IW{1};

% 与工具箱的差异
maxECompareNet = max([max(abs(w(:)-w_tools(:))),max(abs(pyByTool(:)-py(:)))]);
disp(['自写代码与工具箱权重阈值的最大差异:',num2str(maxECompareNet)])

end

% -----------SOM的训练函数----------------------
function w = trainSomNet(X,dimensions,epochs)
[xn,sn] = size(X);                % 输入个数,样本个数
hn      = prod(dimensions);       % 隐节点个数

% ----生成隐节点拓扑结构并计算矩阵矩阵-----------
pos     = hextop(dimensions);     % 生成隐节点拓扑结构
d       = linkdist(pos);          % 隐节点拓扑结构距离矩阵

% --------参数设置--------------
order_steps = 1000;               % 收缩步数阈值
order_lr    = 0.9;                % 初始学习率
tune_lr     = 0.02;               % 学习率收缩阈值
nd_max      = max(max(d));        % 初始邻域距离
tune_nd     = 1 ;                 % 邻域距离收缩阈值

%-----初始化w:取每个输入的中心点-------------------
x_mid  = (min(X,[],2)+max(X,[],2))/2;         % 计算输入的中心点
w      = repmat(x_mid',hn,1);                 % 初始化w

% ---------训练-----------------------------
step   = 0;
for epoch=1:epochs
    for i=1:sn
        idx   = fix(rand*sn) + 1;         % 随机选择一个样本
        cur_x = X(:,idx);                 % 当前选择的样本

        if (step < order_steps)             % 小于order_steps时,线性收缩学习率与邻域
            percent = 1 - step/order_steps;
            nd      = 1.00001 + (nd_max-1) * percent;
            lr      = tune_lr + (order_lr-tune_lr) * percent;
        else                                % >=order_steps时,幂收缩学习率,邻域则不再变化
            nd      = tune_nd + 0.00001;
            lr      = tune_lr * order_steps/step;
        end
        
        a     = predictSomNet(w,cur_x);          % 网络的预测值
        lr_a = lr * 0.5*(a + (d < nd)*a);        % 计算邻域内的节点学习率
       
        % 计算dw
        dw   = zeros(hn,xn);                 
        dw   = dw +repmat(lr_a,1,xn) .* (repmat(cur_x',hn,1)-w);
        
        % 更新w
        w    = w + dw;  
        step = step + 1;
    end
end

end

% --------SOM的预测函数---------------
function y = predictSomNet(w,X)

% 计算隐节点激活值
z = zeros(size(w,1),size(X,2));
for i= 1: size(X,2)
    cur_x = X(:,i);
    z(:,i) = -sum((repmat(cur_x',size(w,1),1)-w).^ 2,2) .^ 0.5;
end
% 通过隐节点竞争得到输出
[~,idx] = max(z);% 找出最大值
y = z*0;
y(idx+ size(y,1)*(0:size(y,2)-1)) = 1;

end



注意:本代码是matlab旧版本神经网络工具箱som代码的逻辑,在新版本上与newsom结果会不一致。




 End 









联系老饼