抓住时间的尾巴,在我还有时间学一点其他东西的时候,尽量做点笔记吧,证明我来过。
今天的东西原理很简单,但是要实现起来还是有点小麻烦的,有很多坑,一不小心就会掉下去。通过理解感知机,我们对神经网络也会有更加深刻的认识。因为这就是神经网络的基础。
先来看看感知机长什么样子:
如图所示,它就是一个最最简单的神经网络(虽然只有一个神经元)。我们现在用它来实现逻辑“与”,也就是说当输入为(1,1)时输出为1,当输入中有0时,输出0 。当然也可以实现“或“、”非”逻辑,但是这是重复工作。(注意并非任何逻辑关系都能实现,比如‘或非’,其原因是在直角坐标其中不能将其结果用一条直线分开。)
来看看它是怎么实现这个逻辑的。
首先,总共有2个输入x1和x0,所以权重也有两个w0,w1,还有阈值θ,后面三者是待确定的。但是通常情况下,将θ视为w3,所以输入就有三个(xi与wi为一一对应关系),只是第三个输入恒为-1。最后的结点表达式为:
现在我们的工作是把t带入激活函数中,来判断f(t)。我们选用的激活函数及其图像为:
(大家喜欢把它叫做sigmoid函数。)回到上一步,我们现在需要判断的是f(t)是否大于0.5,若 f(t)>=0.5 就把结果视为1,反之视为0 。
【注】这种做法仅仅是在设计逻辑函数时的做法。
那么其判断原理我们现在就弄清楚了,现在来看看怎么训练数据。
首先需要确定待确定的变量为w1,w2,w3简称wi。在这里,我们希望根据带入wi与xi后算出的f(t)和数据集中原来的值y(实际值)来作比较,根据其误差大小来改变wi因此,引入公式:
其中β称为学习率,在(0,1)之间。现在可以改变wi了,也就是说可以根据数据集来训练wi了。
但是别高兴太早,还有很多坑。根据我的经验,总结了有几点:
1、我们的数据集格式为【1,1,0.9】或【1,0,0.4】或【0,1,0.3】或【1,1,0,76】……你懂我意思吧。
2、数据集尽量分散,也就是不要【1,1】一群【1,0】一群,这样训练来的wi极为不准确(亲测)。
3、最后输出的时候我们要做一下处理,也就是大于0.5时,我们要让他输出1,小于0.5时,我们要让他输出0 。当然这只是在最后验证结果的时候,
在训练的时候还是要带值的。
下面是我的实现过程:
我造的数据为160×3的数据集,其中【1,1】、【1,0】、【0,1】、【0,0】分别占40个。下面是一次训练的结果。
可以看到,验证结果全对!!为了验证这种训练的准确度,我又设计了对程序加了一个循环,让它运行1000次!!!其中,分类正确的有919次,也就是说正确率达到了91.9%。要是我的训练集再特殊一点,算法再设计得好一些的话,正确率还会增加。(顺便说下,运行1000次大约花25秒,比较耗时。)
附件一(单次训练):
f = inline('1/(1+exp(-x))','x'); %sigmoid函数表达式
theta = 0.5; %学习率
shuju = ones(160,3);%下面几句有关shuju的都是在生成数据集
shuju(41:80,2) = 0;
shuju(81:120,1) = 0;
shuju(121:160,1:2) = 0;
shuju(1:40,3) = rand(40,1)*0.5+0.5;
shuju(41:end,3) = rand(120,1)*0.5;
randindex = randperm(size(shuju,1));%这两句是打乱数据集的顺序
shuju=shuju(randindex,:)
y=shuju(1:end,3);%构造xi
x = shuju;
x(1:end,3) = -1;
w = rand(3,1);%生成初始wi
for i=1:160 %训练
t = x(i,:)*w;
loss = theta*(y(i)-f(t));
for j =1:3
w(j) = w(j)+x(i,j)*loss
end
end
disp('验证') %下面全是验证
disp('带入x=[1,1]')
x1=[1,1,-1];
t = x1*w;
if f(t)>=0.5
disp('1')
else
disp('0')
end
disp('带入x=[0,1]')
x1=[0,1,-1];
t = x1*w;
if f(t)>=0.5
disp('1')
else
disp('0')
end
disp('带入x=[0,0]')
x1=[0,0,-1];
t = x1*w;
if f(t)>=0.5
disp('1')
else
disp('0')
end
disp('带入x=[0,1]')
x1=[0,1,-1];
t = x1*w;
if f(t)>=0.5
disp('1')
else
disp('0')
end
附件二(运行1000次):
f = inline('1/(1+exp(-x))','x'); %sigmoid函数表达式
sum = 0;
for k=1:1000
theta = 0.5; %学习率
shuju = ones(160,3);%下面几句有关shuju的都是在生成数据集
shuju(41:80,2) = 0;
shuju(81:120,1) = 0;
shuju(121:160,1:2) = 0;
shuju(1:40,3) = rand(40,1)*0.5+0.5;
shuju(41:end,3) = rand(120,1)*0.5;
randindex = randperm(size(shuju,1));%这两句是打乱数据集的顺序
shuju=shuju(randindex,:);
y=shuju(1:end,3);%构造xi
x = shuju;
x(1:end,3) = -1;
w = rand(3,1);%生成初始wi
for i=1:160 %训练
t = x(i,:)*w;
loss = theta*(y(i)-f(t));
for j =1:3
w(j) = w(j)+x(i,j)*loss;
end
end
a = 0;%标记
x1=[1,1,-1];
t = x1*w;
if f(t)>=0.5
a=a+1;
end
x1=[0,1,-1];
t = x1*w;
if f(t)<0.5
a=a+1;
end
x1=[0,0,-1];
t = x1*w;
if f(t)<0.5
a=a+1;
end
x1=[0,1,-1];
t = x1*w;
if f(t)<0.5
a=a+1;
end
if a==4
sum=sum+1;
end
sum
end
disp('1000次中正确的次数')
sum
disp('正确率为:')
sum/1000