学习了周志华《机器学习》中的BP神经网络,编代码的时候想找别人的作参考,发现好多人都直接调用工具箱。所得非所求,只能是自己写了代码,仅供新手参考,其中大部分是矩阵直接运算,对鸢尾花2/3数据训练,1/3数据训练。准确率在96%左右。
说明:代码的直接矩阵运算也是我坐那里耗费一些时间自己去想的,所以新手要看懂可能需要一些时间。一些人可能没读过这本书也会感觉云里雾里,鉴于篇幅问题,我在我的资源了上传了直接运行的代码、数据集和《机器学习》相应的理论说明,那里面有详细的梯度项理论推导,地址如下:https://download.csdn.net/download/weixin_44405310/11530170 有书的人自然心领神会。
以下是我的一些学习心得:
**什么是梯度下降法:**在这里我推一篇博文:https://blog.csdn.net/pengchengliu/article/details/80932232 大家可以参考,讲这个的人很多。
数据归一化问题: 有人不理解为什么要数据归一化,我举一个浅显的例子:一个属性集的数据数量级是10
4
^4
4,它的阈值是0.1;另一个属性集的数据数量级是10,就算它的阈值是1,把它们分别乘起来;我们发现数量级是10的那个属性集分明就是鸡肋嘛!影响不了大局。
而matlab自带归一化函数mapminmax好像只能对行归一化,我不想转置,就自己写了一段程序。
分类: 鸢尾花是要分类的,那么输出神经元该怎么办。我们可以这样,看它有几个类别,那就定义几个输出神经元。对本例而言:[0 1 0]就可以说是第二类,刚开始的类别标签也要这么处理。当然计算的输出神经元不可能那么准确,但是非常接近1。总之,就是取最大的位置作为它的类别。其实我还有一个想法,就是把最后的激活函数乘3,只设置一个输出神经元,如果输出是0~1就是第一类, 输出在1~2就判定第二类。
隐层神经元的数目我是随便设的,这个我也不知道设置多少。
clear
clc
f=fopen('C:\Users\HP\Desktop\iris.data');
Iris=textscan(f,'%f%f%f%f%s','delimiter',',');
fclose(f);
[~,n]=size(Iris);
for i=1:n-1
data(:,i)=Iris{1,i};
end
[m,n]=size(data);
for i=1:m
if strcmp(Iris{1,5}{i,1},'Iris-setosa')
data(i,5:7)=[1 0 0];
elseif strcmp(Iris{1,5}{i,1}, 'Iris-versicolor')
data(i,5:7)=[0 1 0];
else
data(i,5:7)=[0 0 1];
end
end
%数据归一化处理[0,1]区间内,
x_max=max(data);
x_min=min(data);
data=(data-ones(m,1)*x_min)./(ones(m,1)*(x_max-x_min));
% 这里可用函数data=mapminmax(data,0,1)替换
%但data需要转置因为mapminmax只能对行进行归一化
%%
%划分训练样本和测试样本 大约2/3用作训练,1/3用作测试
num=round(m/3/3);
for i=1:3
temp=data(1+50*(i-1):50*i,:);
sel=randperm(50,num);
test(1+num*(i-1):num*i,:)=temp(sel,1:4);
test_label(1+num*(i-1):num*i,:)=temp(sel,5:7);
temp(sel,:)=[];
train(1+(50-num)*(i-1):(50-num)*i,:)=temp(:,1:4);
train_label(1+(50-num)*(i-1):(50-num)*i,:)=temp(:,5:7);
end
%%
[m,n]=size(train);
alpha=4;%输入神经元数目
beta=8;%隐层神经元数目
lamda=3;%输出神经元数目
rng('shuffle')
W1=rand(alpha,beta);%输入层和隐层之间的权值矩阵
W2=rand(beta,lamda);%隐层和输出层间的权值矩阵
B1=rand(1,beta);%隐层阈值矩阵
B2=rand(1,lamda);%输出层阈值矩阵
B22=B2;
W11=W1;
Eta=1;%学习率
iter_max=10000;%最大迭代次数
iter=1;
%BP神经网络,每次仅针对一个训练样例更新连接权和阈值
while iter<=iter_max
for i=1:m
hidden_in=train(i,:)*W1;%隐层输入
hidden_out=sigmod(hidden_in-B1);%隐层输出
output_in=hidden_out*W2;%输出层输入
output_out=sigmod(output_in-B2);%输出层输出
%计算误差
E(i)=sum((output_out-train_label(i,:)).^2);%求平方和可用sumsqr函数
%%
%更新参数,BP神经网络中最核心的部分
g=output_out.*(1-output_out).*(train_label(i,:)-output_out);%计算输出层神经元的梯度项
e=hidden_out.*(1-hidden_out).*(g*W2');%计算隐层神经元的梯度项
Deta_W2=Eta*hidden_out'*g;
Deta_B2=-Eta*g;
Deta_W1=Eta*train(i,:)'*e;
Deta_B1=-Eta*e;
W1=W1+Deta_W1;
W2=W2+Deta_W2;
B1=B1+Deta_B1;
B2=B2+Deta_B2;
end
%计算训练集的累积误差
E=mean(E);
if E<1e-4 %目标误差
iter
break
end
if mod(iter,1000)==0
iter
end
iter=iter+1;%更新迭代次数
end
%%
%测试
[result,accuracy]=BP_test(test,test_label,W1,W2,B1,B2);
disp('结果为:')
result';
disp(strcat('准确率为',num2str(accuracy*100),'%'))
function [result,accuracy]=BP_test(test,test_label,W1,W2,B1,B2)
%返回分类的结果
%accuracy准确率
Hidden_in=test*W1;%隐层输入
Hidden_out=sigmod(Hidden_in-B1);%隐层输出
Output_in=Hidden_out*W2;%输入层输入
Output_out=sigmod(Output_in-B2);
[~,result]=max(Output_out,[],2);
[~,index2]=max(test_label,[],2);
right=sum(result==index2);%统计分类正确的个数
total=size(test,1);%总个数
accuracy=right/total;
end
%sigmod函数在matlab里是logsig函数
function [Y]=sigmod(X)
Y=1./(1+exp(-1).^X);
end
这是结果:
ans =
1 至 19 列
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2
20 至 38 列
2 2 2 3 2 2 3 2 2 2 2 2 2 2 2 3 3 3 3
39 至 51 列
3 3 3 3 3 3 3 3 3 3 3 3 3
准确率为96.0784%