本站原创文章,转载请说明来自《老饼讲解-BP神经网络》bp.bbbdata.com
本文是笔者细扒matlab2009b神经网络工具箱newsom的源码,
在源码的基础上去除冗余代码,重现的简版newsom代码,代码与newsom的结果完全一致。
通过本代码的学习,可以完全细节的了解SOM单样本训练的实现逻辑。
代码主要包含了三个函数: testSomNet trainSomNet predictSomNet
testSomNet: 测试用例主函数,直接运行时就是执行该函数。
1、数据生成:随机生成一组训练数据,
2、用自写的函数训练一个SOM网络,与预测结果。
3、使用工具箱训练一个SOM网络。
4、比较自写函数与工具箱训练结果是否一致(权重、训练误差的比较)
trainSomNet:网络训练主函数,用于训练一个SOM神经网络。
单样本训练方式,训练一个SOM神经网络
predictSomNet:用训练好的网络进行预测。
传入需要预测的X,与网络的权重矩阵,即可得到预测结果。
运行代码后,得到预测结果与对比结果,如下:
从中可以看到,自写代码与工具箱的逻辑一致。
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