练习题:
双输入单输出系统:
x1(1)=1 x2(1)=1 d(1)=1
x1(2)=-0.5 x2(2)=-1 d(2)=-1
x1(3)=3 x2(3)=1 d(3)=1
x1(4)=-2 x2(4)=-1 d(4)=-1
建立一个 感知器网络,实现上述样本的分类。
计算出相应的网络权值矩阵w。
1、 题目:
双输入单输出系统:
x1(1)=1 x2(1)=1 d(1)=1
x1(2)=-0.5 x2(2)=-1 d(2)=-1
x1(3)=3 x2(3)=1 d(3)=1
x1(4)=-2 x2(4)=-1 d(4)=-1
建立一个感知器网络,实现上述样本的分类。
计算出相应的网络权值矩阵W。
2、 运算结果:
图1 实现误差输出,得出所求权值矩阵,并对样本实现分类:
图2 用opencv2的画线及画点函数实现样本分类及画出误差变化曲线。
3、 实现步骤及对以上结果的说明:
算法部分:
①初始化:建立一个神经元的感知器,开关函数采用 函数
W阵的初值随机为[6,0.5,0.5],即b=6;步长为0.1.
②对网络施加四组输入, 计算感知器的输出
③计算误差:允许误差为E=0
当E<0,则退出,网络训练结束,当E>=0时:
④调节网络权值系数
⑤令:n=n+1,转步骤2。
画图部分:
主要采用opencv2画线函数line(),画点函数circle()。
4、核心代码及说明:
while(E[n]>0) //E[n]存储每一次循环的总误差,当总误差大于零,进行循环
{
n++;
for(int i=0;i<4;i++)
{
W[1]=W[1]+l*(d[i]-Y[i])*X[i][1];//调节网络权值系数
W[2]=W[2]+l*(d[i]-Y[i])*X[i][2];
Y[i]=W[0]*X[i][0]+W[1]*X[i][1]+W[2]*X[i][2];
if(Y[i]>=0)
Y[i]=1;
else
Y[i]=-1;
e[i]=abs(d[i]-Y[i]); //e[i]存储单个样本误差
}
E[n]=e[0]+e[1]+e[2]+e[3];//每次循环计算一次总误差
cout<<"E["<<n<<"]="<<E[n]<<endl;
}
///进行分类
for(int i=0;i<4;i++)
{
if(Y[i]==1)
cout<<"第"<<i<<"组属于第一类"<<endl;
if(Y[i]==-1)
cout<<"第"<<i<<"组属于第二类"<<endl;
}
4、 总结
通过C++编程实现感知器学习,我对其的原理理解更深刻了,只有通过一次次修改代码和查阅资料才知道自己对算法的些地方存在错误的认识,再不断改进自己的算法。
说明:
用了opencv画图
感知器的原理,张老师的课件有错,还是自己上网查吧。我也不确定我的理解是不是完全正确。
代码
- #include<iostream>
- #include"math.h"
- #include <opencv2/core/core.hpp>
- //#include <opencv2/imgproc/imgproc.hpp>
- #include <opencv2/highgui/highgui.hpp>
- //
- //#include "linefinder.h"
- //#include "edgedetector.h"
- using namespace cv;
- using namespace std;
- int main()
- {
- double W[4][3];
- for(int i=0;i<4;i++)
- {
- W[i][1]=0.5;
- W[i][2]=0.5;
- }
- double X[4][3]={-1,1,1,
- -1,-0.5,-1,
- -1,3,1,
- -1,-2,-1};
- double d[4]={1,-1,1,-1};
- double e[4];
- double E[10]={0,0,0,0,0,0,0,0,0,0};
- double b=5;
- //W[][0]=b;
- for(int i=0;i<4;i++)
- W[i][0]=b;
- double l=0.1;
- /*W[0][1]=rand()%10*0.1;
- W[0][2]=rand()%10*0.1;
- W[1][1]=rand()%10*0.1;
- W[1][2]=rand()%10*0.1;
- W[2][1]=rand()%10*0.1;
- W[2][2]=rand()%10*0.1;
- W[3][1]=rand()%10*0.1;
- W[3][2]=rand()%10*0.1;*/
- cout<<W[0][1]<<endl<<W[0][2]<<endl;
- cout<<W[1][1]<<endl<<W[1][2]<<endl;
- cout<<W[2][1]<<endl<<W[2][2]<<endl;
- cout<<W[3][1]<<endl<<W[3][2]<<endl;
- double Y[4]={0};
- for(int i=0;i<4;i++)
- {
- Y[i]=W[i][0]*X[i][0]+W[i][1]*X[i][1]+W[i][2]*X[i][2];
- //cout<<"Y["<<i<<"]="<<Y[i]<<endl;
- if(Y[i]>=0)
- Y[i]=1;
- else
- Y[i]=-1;
- e[i]=abs(d[i]-Y[i]);
- }
- E[0]=e[0]+e[1]+e[2]+e[3];
- cout<<"E{0]="<<E[0]<<endl;
- //cout<<"e1"<<e[i]<<endl;
- int n=0;
- while(E[n]>0)
- {
- n++;
- for(int i=0;i<4;i++)
- {
- W[i][1]=W[i][1]+l*(d[i]-Y[i])*X[i][1];
- W[i][2]=W[i][2]+l*(d[i]-Y[i])*X[i][2];
- //cout<<W[i][1]<<endl<<W[i][2]<<endl;
- Y[i]=W[i][0]*X[i][0]+W[i][1]*X[i][1]+W[i][2]*X[i][2];
- if(Y[i]>=0)
- Y[i]=1;
- else
- Y[i]=-1;
- e[i]=abs(d[i]-Y[i]);
- //cout<<"e"<<e[i]<<endl;
- }
- E[n]=e[0]+e[1]+e[2]+e[3];
- /*cout<<"Yi"<<Y[i]<<endl;
- cout<<"e["<<i<<"]="<<e[i]<<endl;*/
- cout<<"E["<<n<<"]="<<E[n]<<endl;
- }
- cout<<"W[]="<<endl;
- for(int i=0;i<4;i++)
- {
- for(int j=0;j<3;j++)
- cout<<W[i][j]<<" ";
- cout<<endl;
- }
- //E=e[0]+e[1]+e[2]+e[3];
- cout<<"ok"<<endl;
- /*IplImage *test=cvCreateImage(cvSize(400,400),IPL_DEPTH_16U,0);
- Mat mtx(test);*/
- Mat test(400,400,CV_8UC3,Scalar(130,240,205));//3通道图像
- line(test,Point(20,400-20),Point(20,0),Scalar(0));//因为mat型图像的原点在右上角,所以比较麻烦,要通过计算转换
- line(test,Point(20,400-20),Point(400,400-20),Scalar(0));
- for(int i=0;i<10;i++)
- {
- line(test,Point(20*(i+1),380-20*E[i]),Point(20*(i+2),380-20*E[i+1]),Scalar(220,0,150));
- }
- /*for(int i=0;i<10;i++)
- {
- line(test,Point(20*(i+1),20*E[i]),Point(20*(i+2),20*E[i+1]),Scalar(255));
- }*/
- // Display the test image
- namedWindow("E Image");
- imshow("E Image",test);
- imwrite("test.bmp",test);
- waitKey();
- return 0;
- }
1、 题目:
双输入单输出系统:
x1(1)=1 x2(1)=1 d(1)=1
x1(2)=-0.5 x2(2)=-1 d(2)=-1
x1(3)=3 x2(3)=1 d(3)=1
x1(4)=-2 x2(4)=-1 d(4)=-1
建立一个感知器网络,实现上述样本的分类。
计算出相应的网络权值矩阵W。
2、 运算结果:
图1 实现误差输出,得出所求权值矩阵,并对样本实现分类:
图2 用opencv2的画线及画点函数实现样本分类及画出误差变化曲线。
3、 实现步骤及对以上结果的说明:
算法部分:
①初始化:建立一个神经元的感知器,开关函数采用 函数
W阵的初值随机为[6,0.5,0.5],即b=6;步长为0.1.
②对网络施加四组输入, 计算感知器的输出
③计算误差:允许误差为E=0
当E<0,则退出,网络训练结束,当E>=0时:
④调节网络权值系数
⑤令:n=n+1,转步骤2。
画图部分:
主要采用opencv2画线函数line(),画点函数circle()。
4、核心代码及说明:
while(E[n]>0) //E[n]存储每一次循环的总误差,当总误差大于零,进行循环
{
n++;
for(int i=0;i<4;i++)
{
W[1]=W[1]+l*(d[i]-Y[i])*X[i][1];//调节网络权值系数
W[2]=W[2]+l*(d[i]-Y[i])*X[i][2];
Y[i]=W[0]*X[i][0]+W[1]*X[i][1]+W[2]*X[i][2];
if(Y[i]>=0)
Y[i]=1;
else
Y[i]=-1;
e[i]=abs(d[i]-Y[i]); //e[i]存储单个样本误差
}
E[n]=e[0]+e[1]+e[2]+e[3];//每次循环计算一次总误差
cout<<"E["<<n<<"]="<<E[n]<<endl;
}
///进行分类
for(int i=0;i<4;i++)
{
if(Y[i]==1)
cout<<"第"<<i<<"组属于第一类"<<endl;
if(Y[i]==-1)
cout<<"第"<<i<<"组属于第二类"<<endl;
}
4、 总结
通过C++编程实现感知器学习,我对其的原理理解更深刻了,只有通过一次次修改代码和查阅资料才知道自己对算法的些地方存在错误的认识,再不断改进自己的算法。