资源描述
自联想与异联想实验
摘要:实验分为两部分,第一,验证0-2的线性自联想;第二,实现A-J到0-9的异联想。本次实验利用C语言编程实现,最后通过实验结果分析线性联想器的联想和容错性能。
关键词:自联想;异联想;C语言
一、 实验目的
1. 了解线性联想器的原理与结构
2. 实现简单的自联想
3. 实现A-J到0-9的异联想
4. 通过结果分析线性联想器的性能
二、 实验工具与方法
1. 自联想简介
自联想神经网络(Auto-Associative Neural Network , 缩写为AANN)是1992年Kramer提出的,是BP神经网络的一种特殊情形。其特点是有对称拓扑结构,即输出量等于输入量。
2. 异联想简介
异联想与自联想类似,不同之处在于输出与输入不等(Pi!=Ti)。
3. 线性联想器结构如图1所示
图1 线性联想器
如图1所示,P为输入向量,维数R*1,W为权值矩阵,维数S*R,a为联想器的输出向量,维数S*1。
三、 实验内容
1. 验证0-2的自联想
1.1 网络的设计与预处理
自联想网络的设计如图2所示。
图2 实验一自联想网络
如图所示,输入向量P的维数是30*1,权值矩阵W是30*30的方阵,网络输出向量a的维数是30*1,选择的激励函数为硬极限函数(取值为1或-1)。
预处理主要是实现0-2数字的数字图像化,每个数字用一张6*5的图像表示。下图3给出了0-2对应的数字图像。数字0对应的向量形式为:
P[0][30]={-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,-1};
-1
1
1
1
-1
1
-1
-1
-1
1
1
-1
-1
-1
1
1
-1
-1
-1
1
1
-1
-1
-1
1
-1
1
1
1
-1
1
1
1
-1
-1
-1
-1
-1
1
-1
-1
-1
-1
1
-1
-1
1
1
-1
-1
-1
1
-1
-1
-1
-1
1
1
1
1
-1
1
1
-1
-1
-1
-1
1
-1
-1
-1
-1
1
-1
-1
-1
-1
1
-1
-1
-1
-1
1
-1
-1
-1
-1
1
-1
-1
0 1 2
图3 0-2图像表示
1.2 实验步骤
首先根据下面的公式计算出对应的权值矩阵W,然后将P输入,获取联想器输出的结果a,然后判断a与P是否相等。
最后在完成初始验证的情况下,分3组进一步测试,第1组将原图像隐去50%,第2组将原图像隐去67%,第3组进行带噪声的测试。通过实验的结果分析自联想联想器性能。
2. A-J到0-9异联想
2.1 网络的设计与预处理
因为本次实验的异联想实在自联想网络的基础上扩展来的,所以网络的设计不变,预处理的过程也是类似的,只是把0-2扩展到0-9。预处理中需要添加期望输出矩阵T[10][30],用来存放A-J图像数据。
2.2 实验步骤
异联想用到了仿逆规则,首先需要根据公式计算出P+,然后求出权值矩阵W,最后验证网络能否实现A-J到0-9的异联想。
仿逆规则:
验证: Ti=hardlims(W*Pi)
四、 实验结果
1. 自联想测试结果
实验1结果如图4所示。(样本为做处理)
图4 实验1结果
实验2结果如图5所示。(隐去原数据50%)
图5 隐去50%的结果
实验3结果如图6所示。(隐去元数据67%)
图6 隐去67%的结果
实验4结果如图7所示。(加入噪声测试)
图7 加入噪声测试结果
2. 异联想测试结果
实验1输入未处理的A-J,如图8所示。
图8 原始输入数据
对应0-9的输出,如图9所示。
图9 异联想实验结果
实验2输入隐藏50%的A-J,如图10所示。
图10 实验1测试数据输入效果
对应0-9的输出,如图11所示。
图11 隐去50%的异联想结果
五、 实验分析
通过本次线性联想器实验,可以发现自联想阶段,联想器在隐去50%数据和存在噪声的情况下比较完整的联想出了理想的结果,在隐去67%数据时,联想器只识别出了数字1。因此,线性联想器在一般情况下(数据缺失、损坏较小时)联想比较容易,当数据大量失真时,则难以联想出来。因此可以认为线性联想器具有一定的容错能力,但是它的容错能力比较弱。
本次实验中异联想阶段,首先实现了简单的联想,通过实验结果可以看出简单的异联想还是可以完美的实现的。然后进行了隐去50%数据的异联想测试,可以清楚的发现结果并不理想,A-J的10个字母,只识别出D-3,F-5和I-8。
最后,我认为可能是学习规模从0-2扩大到0-9的缘故,实验中异联想的容错性能较实验一自联想有所降低。还有本次实验主要模仿了书中的例子,因此实现起来比较容易,唯一的难点就是在异联想实验中需要用到矩阵求逆过程。因为我是用的C语言写的实现程序,之前在网上找可以求逆的库函数没找到,所以就自己写了一个递归求10阶以内逆矩阵的函数,效果还行,效率不高,运行速度有点慢。
六、 源程序
1. 0-2自联想源代码:
#include<stdio.h>
void show_answer(int n, int array[3][30]) //输出结果函数
{
int i=0;
int j=0;
int k=0;
int temp[6][5]={0}; //temp[6][5]存放一个数字图像信息
for(i=0;i<n;i++)
{
int q=0;
for(j=0;j<5;j++)
{
for(k=0;k<6;k++)
{
temp[k][j]=array[i][q];
q++;
}
}
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
if(temp[j][k]==1)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
printf("\n\n");
}
}
void compute_answer(int n,int array[3][30],int w[30][30], int a[3][30])
{
int i,j,k;
for(i=0;i<n;i++)
{
for(j=0;j<30;j++)
{
a[i][j]=0; //初始化a矩阵
}
}
for(i=0;i<n;i++)
{
for(j=0;j<30;j++)
{
for(k=0;k<30;k++)
{
a[i][j]+=w[j][k]*array[i][k]; //计算a=W*p
}
if(a[i][j]>0) //计算通过激励函数的实际值
{
a[i][j]=1;
}
else
{
a[i][j]=-1;
}
}
}
}
void main()
{
int w[30][30]={0};
int ps[3][30]={{-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,-1} ,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
,{1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,-1,1,-1,1,-1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1}};
//原始0-2数据
int pt_50[3][30]={{-1,1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1} ,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
,{1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1}};
//隐去50%后0-2数据
int pt_67[3][30]={{-1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
,{1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}};
//隐去67%后0-2数据
int pt_mix[3][30]={{-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,1,-1}
,{-1,-1,1,-1,-1,1,1,-1,-1,-1,-1,1,1,1,1,-1,1,1,-1,1,-1,-1,-1,1,-1,-1,-1,1,-1,-1}
,{-1,-1,-1,-1,-1,1,1,1,-1,1,-1,1,1,-1,-1,1,-1,1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,-1,1}};
//加入噪声的0-2数据
int a[3][30]={0};
int i,j,k;
printf("原标准样本: \n");
show_answer(3,ps);
for(i=0;i<3;i++)
{
for(j=0;j<30;j++)
{
for(k=0;k<30;k++)
{
w[j][k]+=ps[i][j]*ps[i][k]; //计算权值矩阵
}
}
}
printf("\n");
printf("标准样本验证: a=hardlims(wp)=p?\n");
compute_answer(3,ps,w,a);
show_answer(3,a);
printf("\n");
printf("隐去样本50%%后效果: \n");
show_answer(3,pt_50);
printf("\n");
printf("隐去样本50%%后测试效果: \n");
compute_answer(3,pt_50,w,a);
show_answer(3,a);
printf("\n");
printf("隐去样本67%%后效果: \n");
show_answer(3,pt_67);
printf("\n");
printf("隐去样本67%%后测试效果: \n");
compute_answer(3,pt_67,w,a);
show_answer(3,a);
printf("加入噪点的样本效果: \n");
show_answer(3,pt_mix);
printf("加入噪点的测试效果: \n");
compute_answer(3,pt_mix,w,a); show_answer(3,a); }
2. A-J异联想源代码:
#include<stdio.h>
float get_hls(int n,float a[10][10]) //计算矩阵的行列式
{
float det=0;
if(n==2)
{
return a[0][0]*a[1][1]-a[0][1]*a[1][0];
}
int i,j,k;
float sub_a[10][10]={0};
for(i=0;i<n;i++)
{
for(j=0;j<n-1;j++)
{
for(k=0;k<n-1;k++)
{
if(k>=i)
{
sub_a[j][k]=a[j+1][k+1];
}
else
{
sub_a[j][k]=a[j+1][k];
}
}
}
if(i%2==0)
{
det=det+a[0][i]*get_hls(n-1,sub_a);
}
else
{
det=det+(-1)*a[0][i]*get_hls(n-1,sub_a);
}
}
return det;
}
void get_bs(int n,float a[10][10],float b[10][10]) //计算所给矩阵的伴随矩阵
{
int i,j,k,l;
float count=0;
float sub_a[10][10]={0};
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
count=0;
for(k=0;k<n-1;k++) //计算代数余子式
{
for(l=0;l<n-1;l++)
{
if(k>=i&&l>=j)
{
sub_a[k][l]=a[k+1][l+1];
}
else if(k>=i&&l<j)
{
sub_a[k][l]=a[k+1][l];
}
else if(k<i&&l>=j)
{
sub_a[k][l]=a[k][l+1];
}
else
{
sub_a[k][l]=a[k][l];
}
}
}
count=get_hls(n-1,sub_a);
if((i+j)%2==0)
{
b[j][i]=count;
}
else
{
b[j][i]=-count;
}
}
}
}
void get_njz(int n,float p,float b[10][10],float c[10][10]) //计算所给矩阵的逆矩阵
{
int i,j;
if(p==0)
{
printf("|a|=0,a不存在逆矩阵\n");
}
else
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
c[i][j]=b[i][j]/p;
}
}
}
}
void main()
{
int i,j,k;
float p[10][30]={{-1,-1,1,1,1,1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,1,1,1}
,{1,1,1,1,1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1}
,{-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,-1,-1,1,-1}
,{1,1,1,1,1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,-1}
,{1,1,1,1,1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1}
,{1,1,1,1,1,1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,-1,-1,-1,-1}
,{-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,1,1,-1,-1,1,-1,1,1,1}
,{1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,1,1,1,1,1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1}
,{-1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,1,1,1,1,1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}};
//A-J原始数据
float p_test[10][30]={{-1,-1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1}
,{1,1,1,1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,-1,1,-1,-1}
,{-1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1}
,{1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,1,-1,-1}
,{1,1,1,1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1}
,{1,1,1,1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,-1,-1,-1,-1}
,{-1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1}
,{1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,1,1,1,-1,-1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}};
//A-J隐去50%的数据
float t[10][30]={{-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,-1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
,{1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,-1,1,-1,1,-1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1}
,{-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1}
,{1,1,1,1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1}
,{-1,-1,-1,-1,-1,-1,1,1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1}
,{-1,1,1,1,1,-1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1}
,{1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1}
,{-1,1,-1,1,1,-1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1}
,{-1,1,1,-1,-1,-1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,-1,1,1,1,1,-1}};
//0-9标准输出
float pT[30][10]={0}; //pT为矩阵p的转置
float p_test_T[30][10]={0}; //p_test_T为矩阵p_test转置
float p_1[10][30]={0}; //p_1为公式中的p+
float temp[10][10]={0}; //temp=pT*p
float hls=0; //hls记录矩阵行列式
float temp_1[10][10]={0}; //temp_1存放temp的伴随矩阵
float temp_2[10][10]={0}; //temp_2存放temp的逆矩阵
float w[30][30]={0}; //权值矩阵w
float result[30][10]={0}; //result存放最后结果
float tT[30][10]={0}; //tT为t转置
printf("输入A-J\n");
for(i=0;i<10;i++) //输出标准的A-J数据
{
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
if(p[i][j+6*k]==1)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
printf("\n");
}
for(i=0;i<10;i++) //计算矩阵p,p_test的转置
{
for(j=0;j<30;j++)
{
p_test_T[j][i]=p_test[i][j];
pT[j][i]=p[i][j];
}
}
printf("输出原矩阵\n");
for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
for(k=0;k<30;k++)
{
temp[i][j]+=p[i][k]*pT[k][j]; //temp=p*pT
}
printf("%-8.2f",temp[i][j]);
}
printf("\n");
}
hls=get_hls(10,temp);
printf("矩阵行列式=%.4f\n",hls);
get_bs(10,temp,temp_1);
get_njz(10,hls,temp_1,temp_2);
printf("输出逆矩阵\n");
for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
printf("%-8.2f",temp_2[i][j]);
}
printf("\n");
}
for(i=0;i<10;i++)
{
for(j=0;j<30;j++)
{
for(k=0;k<10;k++)
{
p_1[i][j]+=temp_2[i][k]*p[k][j]; //计算P+
}
}
}
printf("\n");
for(i=0;i<10;i++)
{
for(j=0;j<30;j++)
{
tT[j][i]=t[i][j]; //为了方便计算,求矩阵t的转置
}
}
for(i=0;i<30;i++)
{
for(j=0;j<30;j++)
{
for(k=0;k<10;k++)
{
w[i][j]+=tT[i][k]*p_1[k][j]; //计算出权值矩阵W
}
}
}
for(i=0;i<30;i++)
{
float count;
for(j=0;j<10;j++)
{
count=0;
for(k=0;k<30;k++)
{
count+=w[i][k]*pT[k][j]; //验证W*P=T
}
if(count>0)
{
result[i][j]=1;
}
else
{
result[i][j]=-1;
}
}
}
for(i=0;i<10;i++) //输出识别结果
{
for(j=0;j<6;j++)
{
for(k=0;k<5;k++)
{
if(result[j+6*k][i]==1)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
printf("\n");
}
}
展开阅读全文