赞
踩
三层前向神经网络应该是神经网络最原始、最简单的网络结构了,顾名思义,它只包含了三层结构——输入层、隐藏层、输出层。其基本原理很简单,主要是加权求和,再加个激活函数,运算的知识点没有超过初中数学。
人工神经网络是收到人脑结构启发的一种算法。人脑神经元通过突触两两相连,将信息传递给下一个树突,树突将得到的数据经过处理(激活),继续传递给下一个神经元。受到这样结构的启发,人们提出了人工神经元结构来模拟真实神经元的工作过程,如下图所示。
假设一个神经元前面连接了d个神经元,该神经元接受的输入是分别来自前一层神经元的输出x1…xd。每个输入对该神经元作用的大小不同,因此每个输入对应不同的权重w1…wd,经过加权求和,这个神经元所接受的输入总量为:w1*x1 + w2*x2 + … + wd*xd。当然,神经元也不会就将这个值全盘输出给下一层,而是有筛选性地输出,就像我们的大脑如果接受大量信息而不经过筛选,那迟早得累死。这个筛选的标准就是一个激活函数,以前比较常用tanh、sigmoid函数,现在实际应用中ReLu更常用。
如果没有激活函数,整个网络相当于一个线性函数,即输出为输入x的加权求和,并不能起到分类的作用。引入激活函数其实就是引入了非线性因素。
给定n个训练样本X,每个训练样本维度为d,对应标签T。举个实际的例子,用Matlab生成5类不同高斯分布的点,各两百个,每个点的维度为2,即横坐标和纵坐标。
那么,神经网络的输入层需要d+1个节点,多出来一个节点输入1作为样本的偏置。这里的x上标i表示第i个样本,下标j表示第j个节点。如下图所示,因为样本x的维度是2,分别输入每一个样本的每一维度的值,再加上一个偏置1.
隐藏节点对应上图蓝色的点。z = W·x,隐藏层的输入是输入层的加权,权重矩阵Wh的第i行对应输入层对隐藏层第i个节点的权重。隐藏层的输入经过tanh激活得到输出a,f(z)=a。
隐藏层的输出a同样经过对应的权重加和,就设这个加和为u吧,然后同样经过一个激活函数sigmoid得到预测值y。
sigmoid函数图像如上,中间原点对应值为0.5,两边无限趋近于0和1。sigmoid作为激活函数,那么神经元输出的值区间是(0,1)。越接近于1,表示预测概率越大;越接近0,表示预测结果越小。分类结果选取概率最大的y所对应类别标签。
采用反向传播,公式太多,还是另外再开一坑吧。
本次仿真共1000个样本点,取600个作为训练集,400个作为验证集,共有5类样本。采用100样本的小批量下降方法,分别对不同学习速率和不同隐藏节点个数的训练准确率作了比较。结果显示节点个数为10、学习速率为0.01时效果较好。
采用随机梯度下降的方法,每一次的迭代速度快,但是收敛慢且震动大。采用批梯度下降的算法震动最小,但是迭代时间长,迭代1000次左右收敛。100样本小批量梯度下降震荡程度适中,收敛速度最快,差不多训练400次就收敛了,最高准确率在97%左右。下面分别是随机梯度、100小批量、批梯度下降运行结果对比。
参考网上的代码,自己有做了进一步修改
Sigma = [1, 0; 0, 1]; mu1 = [1, -1]; x1 = mvnrnd(mu1, Sigma, 200); mu2 = [5, -4]; x2 = mvnrnd(mu2, Sigma, 200); mu3 = [1, 4]; x3 = mvnrnd(mu3, Sigma, 200); mu4 = [6, 4]; x4 = mvnrnd(mu4, Sigma, 200); mu5 = [7, 0.0]; x5 = mvnrnd(mu5, Sigma, 200); %---------------------main---------------------% %读入数据 X_train = [x1(1:120,:);x2(1:120,:);x3(1:120,:);x4(1:120,:);x5(1:120,:)]; X_test = [x1(121:200,:);x2(121:200,:);x3(121:200,:);x4(121:200,:);x5(121:200,:)]; t = zeros(600,5); t(1:120,1) = 1; t(121:240,2) = 1; t(241:360,3) = 1; t(361:480,4) = 1; t(481:600,5) = 1; tt = zeros(400,5); tt(1:80, 1) = 1; tt(81:160, 2) = 1; tt(161:240, 3) = 1; tt(241:320, 4) = 1; tt(321:400, 5) = 1; param.Nx = 600; %训练数 param.Nd = 3; %输入x的维度 param.Ny = 5; param.Nh = 10; %隐藏节点个数 param.eta = 0.01; %权重更新率 param.theta = 1; %停止阈值 %初始化 Wh = 0.2*(rand(param.Nd,param.Nh)-0.5); Wy = 0.2*(rand(param.Nh,param.Ny)-0.5); w{1} = Wh; w{2} = Wy; param.batch_size = 100; %[J, z, yh] = forward(X_train, w, t, param); %批梯度下降 [ w1, count1, data1, acc] = batchBP( X_train, X_test, w, t, tt, param ); %单样本方式更新权重 %[w2, count2, data2] = singleBP( X_train, X_test, z, yh, w, t, tt, param ); %绘图 n1 = numel(find(data1 > 0)); data1 = data1(1:n1); acc = acc(1:n1); xx1 = 1:n1; figure(1); plot(xx1,data1); xlabel('迭代次数') ylabel('目标函数loss') figure(2); plot(xx1, acc); xlabel('迭代次数') ylabel('正确率') function [J,z,yh] = forward(x, w, t, Nx) %x为输入样本,w为网络权重,t为输出真值,param为网络参数 %J为损失函数,z为最后一层输出,yh为隐藏层输出 %Nh = param.Nh; %Nx = param.Nx; %Nd = param.Nd; %Ny = param.Ny; Wh = w{1}; Wy = w{2}; neth = x * Wh; yh = tanh(neth); netj = yh * Wy; z = sigmoid(netj); J = zeros(Nx,1); for k = 1:Nx J(k) = 0.5 * sum((z(k,:) - t(k,:)).^2); % J(k) = 0; % for i = 1:Ny % J(k) = 0.5 * (z(k,i) - t(k,i))^2 + J(k); % end end end function [ w, q, data, acc] = batchBP( x, x_t, w, t, tt, param ) %BATCHBP 此处显示有关此函数的摘要 % 批量BP算法 Nh = param.Nh; %Nx = param.Nx; Nx = param.batch_size; Nd = param.Nd; Ny = param.Ny; eta = param.eta; theta = param.theta; flag = 0; % res = [0 0 0]; % resid = 1; data = zeros(30000,1); acc = zeros(30000,1); q = 0; %迭代次数 q = count while(flag == 0) %根据次数划分每一次的训练数据 m = mod(q, 6); x_batch = x(1+m*100: (m+1)*100, :); t_batch = t(1+m*100: (m+1)*100, :); Wh = w{1}; Wy = w{2}; [ J, z, yh ] = forward( x_batch, w, t_batch, Nx ); sj = zeros(Nx,Ny); sh = zeros(Nx,Nh); deltaj = zeros(Nh,Ny); deltah = zeros(Nd,Nh); for k = 1:Nx for j = 1:Ny sj(k,j) = z(k,j)*(1-z(k,j))*(t_batch(k,j)-z(k,j)); for h = 1:Nh deltaj(h,j) = eta*sj(k,j)*yh(k,h) + deltaj(h,j); end end for h = 1:Nh sh(k,h) = (1-yh(k,h)^2)*(Wy(h,:)*sj(k,:)'); for i = 1:Nd deltah(i,h) = eta*sh(k,h)*x_batch(k,i) + deltah(i,h); end end end Wy = Wy + deltaj; Wh = Wh + deltah; w{1} = Wh; w{2} = Wy; %[ J, z, yh ] = forward( x, w, t, param ); JJ = sum(abs(J)); [ out ] = test( w, x_t, tt ); q = q + 1; data(q) = JJ; acc(q) = out; % res(resid) = JJ; % resid = resid + 1; % if resid == 4 % resid = 1; % end if JJ < theta || isnan(JJ) || q==3000 %(round(res(1),3) == round(res(2),3) && round(res(1),3) == round(res(3),3)) flag = 1; end disp(['batch迭代第' num2str(q) '次,正确率为:' num2str(out*100) '%, loss为:' num2str(JJ)]); end end function [ out ] = test( w, X_test, tt ) %TEST 此处显示有关此函数的摘要 % 此处显示详细说明 Wh = w{1}; Wy = w{2}; neth = X_test * Wh; yh = tanh(neth); netj = yh * Wy; z = sigmoid(netj); [~,I] = max(z,[],2); %返回每行最大的数所在的列数 [~,It] = max(tt,[],2); tr = numel(find(I == It)); %判断正确的数目 out = tr/size(X_test,1); end function [ y ] = sigmoid( x ) %SIGMOID 此处显示有关此函数的摘要 % 此处显示详细说明 [a,b] = size(x); y = zeros(a,b); for i = 1:a for j = 1:b y(i,j) = 1/(1+exp(-x(i,j))); end end end
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。