MLP-多层感知机的原理及Matlab实现

2019-04-13 15:20发布

前言

这个程序前前后后写了一两周了,一直拖拖拉拉,今天趁着阳光太大,怕晒黑,躲在寝室一下午终于调试出来了。在此记录一下多层感知机模型的原理以及我自己的感悟。如果有任何疑问欢迎大家跟我讨论:shitianqi1994@163.com

感知机matlab实现

关于这个看过很多资料,很多资料好像还将感知机和人体大脑感知系统联系起来什么的,深深的一个白眼。。。根本没必要说的多么高大上,学过模电的同学就很好理解,其实每个感知器都相当于一个二极管,将很多很多二极管组合在一起就可以完成一个逻辑电路,实现我们需要的功能。不同的只是这个“二极管“的参数是机器自己更新学习到的而已。 感觉网上关于感知机的基础知识很多,这里直接甩上我的代码供大家参考。
  • 代码说明
这个代码的[作用]是用感知机对字母“O“和“D“做分类(可以做任意数字的区分,可以修改代码使用),数据在letter_recognition百度云盘供大家测试使用。 我的代码使用[随机梯度下降],耗时比较长,准确率只能达到92%左右,使用batch_gradient descend应该会进一步改善,之后有时间将会进一步修改完善代码。 学习速率:0.01
loss下线:0.38
这些参数均可以修改。
  • 代码片
%% % 处理数据每行读取数据,如果是o或者d,存入数组 % src=fopen('/Users/sdd/Desktop/letter-recognition.data'); uiimport('/Users/sdd/Desktop/letter-recognition.data'); all_data_src=[]; all_label=[]; for i=1:20000 if letterrecognition{i,1}=='O' all_data_src=[all_data_src;[letterrecognition(i,2:end)]]; all_label=[all_label;1]; end if letterrecognition{i,1}=='D' all_data_src=[all_data_src;[letterrecognition(i,2:end)]]; all_label=[all_label;0]; end end all_data_src=cell2mat(all_data_src); %% % 将所有数组进行pca降维 [m,n]=size(all_data_src); data_number=m; feature_src_number=n; [COEFF,SCORE,latent]=princomp(all_data_src); for i=1:feature_src_number if sum(latent(1:i))/sum(latent)>=0.95 all_data=all_data_src(:,1:i); break; end end [m1,n1]=size(all_data); data_number=m1; feature_number=n1; % % % 将所有数据分成测试集和训练集 train_number=floor(m1*0.7); train_label=all_label(1:train_number); test_label=all_label(train_number+1:end); train_data=all_data(1:train_number,:); test_data=all_data(train_number+1:end,:); % % % 用mlp_1hidden进行训练,得到训练准确率和测试准确率 % % % [train_accuracy,test_accuracy] = mlp_1hidden(train_data,train_label,test_data,test_label); [m1,n]=size(train_data); [m2,n2]=size(test_data); feature_number=n; train_data_number=m1; test_data_number=m2; % 中间层个数的初始化 hidden_layer_number=3; % 权值的初始化,令其为很小的高斯分布随机数 w1=0.1*randn(feature_number,hidden_layer_number); w2=0.1*randn(hidden_layer_number,1); % bias的初始化 b1=ones(1,hidden_layer_number); b2=1; while 1 % 得到每个train data的预测数值 predict_list=zeros(train_data_number,1); for i=1:train_data_number y1_original=train_data(i,: )*w1; y1=y1_original+b1; y1=sigmoid(y1); y2_original=y1*w2; y2=y2_original+b2; y2=sigmoid(y2); %%%y2为预测值 predict_list(i,:)=y2; end % 计算loss值 loss_sum=0; for i=1:train_data_number loss_for_single=0.5*(1/train_data_number)*(train_label(i,:)-predict_list(i,:))^2; loss_sum=loss_sum+loss_for_single; end % 当loss小于0.001时,得到最优结果跳出,可以更改数值得到不同精度 loss_sum if loss_sum<0.038 break; end % 使用梯度下降更新权值 % 设置每层的学习速率 learning_rate_w1=0.01; learning_rate_w2=0.01; % 任意选取一个点,计算其各个量值以便后续的随机梯度下降 choosen_point=randperm(train_data_number,1); choosen_data=train_data(choosen_point,:); choosen_label=train_label(choosen_point); y22=sigmoid(choosen_data*w1+b1); y=sigmoid(y22*w2+b2); % 对中间隐藏层进行随机梯度下降 % % loss_gradient为w1,w2的关于loss function的梯度 loss_gradient_w2=zeros(hidden_layer_number,1); loss_gradient_b2=(choosen_label-y)*y*(1-y); for i=1:hidden_layer_number loss_gradient_w2(i,:)=(choosen_label-y)*y*(1-y)*y22(:,i); end % 完成w2的梯度更新 w2=w2+learning_rate_w2*loss_gradient_w2; b2=b2+learning_rate_w2*loss_gradient_b2; % 对输入层进行随机梯度下降 loss_gradient_w1=zeros(feature_number,hidden_layer_number); for i=1:feature_number for j=1:hidden_layer_number loss_gradient_w1(i,j)=(choosen_label-y)*y*(1-y)*w2(j,:)*(1-y22(:,j))*y22(:,j)*choosen_data(:,i);%%%%%%%% end end loss_gradient_b1=zeros(1,hidden_layer_number); for i=1:hidden_layer_number loss_gradient_b1(:,j)=(choosen_label-y)*y*(1-y)*w2(j,:)*(1-y22(:,j))*y22(:,j); end % % 完成w1的梯度更新 w1=w1+learning_rate_w1*loss_gradient_w1; b1=b1+learning_rate_w1*loss_gradient_b1; end % 用最终的w1,w2得到的predict_list计算train_accuracy %%写出预测label predict_label_list=zeros(train_data_number,1); for i=1:train_data_number if predict_list(i,:)>0.5 predict_label_list(i,:)=1; else predict_label_list(i,:)=0; end end judge_list=train_label-predict_label_list; accurate_count=length(find(judge_list==0)) train_accuracy=accurate_count/train_data_number 感谢大家的阅读,有问题欢迎讨论。