Hopfield网络及C#实现

版权所有:基础软件。作者邮箱:sun.j.l.studio@gmail.com。本文首发于 http://www.cnblogs.com/FoundationSoft。文章转载请保持此版权信息并注明出处。

最近在看一本书, Introduction to Neural Networks for CSharp。其中有一章介绍了Hopfield网络。这章对于Hopfield的介绍很简单,其运行过程用C#来实现也很容易,只是没有介绍网络运行的原理、数学证明,程序即使运行出来了,也是知其然不知其所以然。我从网上查了一些资料,期望找到Hopfied网络的数学理论基础和训练方法有效性的数学证明,但是暂时没有找到和书上所说的训练方法一致的相关内容,却意外发现另外一个问题对:大家对Hopfield网络模型以及训练的描述都有一些差异,没有完全一致的定义。看来以后还要多看各种资料,自己消化理解,对别人所说的做出甄别。
  不管怎么说,书上介绍的内容简单实用,按照书上的训练方法能够识别一些简单的模式。这篇文章把书中讲的Hopfield网络训练和识别方法做一归纳总结。
  书中定义的Hopfield网络是一种单层全互连自动联想网络(fully connected single layer autoassociative network)。书中所讲的Hopfield网络有以下几个特点:  (1)网络有N个神经元,则权值矩阵W为N*N的方阵。权值矩阵W为对称阵,且对角线元素为0.即神经元到自身的权值为0。
  (2)神经元输入为二值(即0、1或者-1、1),书中采用0和1.
  (3)神经元输出为二值(即0、1或者-1、1),书中采用0和1.
  训练过程如下:
  (1)初始化权值矩阵为0.
  (2)输入下一个模式P,P为N维向量(p1,p2,p3...pn)。
  (3)将p乘以p的转置得到一个N*N的方阵A。
  (4)将第3步的方阵A对角线元素设置为0.
  (5)将方阵A回到权值矩阵W上。
  (6)如果有更多的模式,则转到第2步。
  (7)训练结束。  训练结束后,可以用Hopfield网络识别前面的训练模式,或者与它们相近的模式,这体现了Hopfield的联想功能。Hopfield能够自动识别与其训练模式相反的模式,例如训练模式为[0,1,1,0],则训练后,网络也能识别[1,0,0,1]。
  利用Hopfield网络可以实现简单的图形识别,如数字识别。把图形拆成点阵,形成一个二维矩阵,把矩阵拉成一维的向量,这就是Hopfield网络要识别的模式了。将这个模式输入给Hopfield网络训练即可。
  Hopfield网络的C#代码实现如下。下面的代码中用到了矩阵类Matrix,这是我写的一个类,封装了常用的矩阵运算,代码在这里

 

Hopfield网络代码
/// <summary>
/// Hopfield网络,单层全互联自动联想网络,输入为二值。
/// </summary>
/// <remarks>
/// 孙继磊,2010-10-18
/// sun.j.l.studio@gmail.com
/// </remarks>
public class HopfieldNetwork
{
#region 属性和字段
private Matrix weightMatrix;
/// <summary>
/// 权值矩阵
/// </summary>
public Matrix weight
{
get
{
return weightMatrix;
}
}
/// <summary>
/// 神经元数量
/// </summary>
public int size
{
get
{
return weightMatrix.rowNum;
}
}
#endregion

#region 构造函数
/// <summary>
/// 构造一个指定大小的Hopfield网络
/// </summary>
/// <param name="size">神经元数量</param>
public HopfieldNetwork(int size)
{
this.weightMatrix = new Matrix(size, size);

}
#endregion
/// <summary>
/// 输入一个模式计算得到输出(输入输出都是二值向量)
/// </summary>
/// <param name="pattern">输入的模式</param>
/// <returns>输出结果</returns>
public bool[] Present(bool[] pattern)
{
bool[] output = new bool[pattern.Length];
//将模式转换为矩阵(行向量)
Matrix row = new Matrix(BipolarUtil.Bipolar2double(pattern));
//计算输出
for (int c = 0; c < pattern.Length; c++)
{
Matrix column
= weightMatrix.getColumn(c);
double dotProduct = (row * column)[0,0];
output[c]
= dotProduct > 0;
}
return output;
}

/// <summary>
/// 针对某一模式进行训练
/// </summary>
/// <param name="pattern">要训练的模式</param>
public void Train(bool[] pattern)
{
if (pattern.Length != weightMatrix.rowNum)
throw new AnnException("输入模式维数与Hopfield神经元数量不匹配。");

// 将输入模式转换为行向量
Matrix input = new Matrix(BipolarUtil.Bipolar2double(pattern));
// 输入行向量转置得到列向量
Matrix inpute2 = Matrix.transpose(input);
//输入行向量与转置相乘,得到矩阵后,对角线设置为0
Matrix t = inpute2 * input;
for (int i = 0; i < input.columnNum; i++)
t[i, i]
= 0;
//将前面计算得到的矩阵回到原来的权值矩阵
weightMatrix = weightMatrix + t;
}
}

用于测试Hopfield网络的代码如下。这段代码用8个神经元识别2个预定义的模式01011100和00111111,而且由于Hopfield网络的联想记忆功能,可以识别与训练样本近似的模式,这在模糊识别时非常有用。

根据这个例子的代码和思想,较容易写出数字识别的程序来。就是把数字图形编成点阵,并将这个点阵拉直成行向量,作为Hopfield网络的训练样本即可。例如将0-9数字每个图案做成16*16的点阵,则需要16*16=256个神经元。当然应该用不了这么多,具体数量可通过实验来决定。

下面的代码是我用8个神经元识别2个模式的例子。先用标准样本训练,后让用户输入模式并识别。

Hopfield网络测试代码
1 /// <summary>
2  /// 由8个神经元组成简单的Hopfield网络,识别简单的模式
3  /// </summary>
4 public void simplePattern()
5 {
6 const int SIZE = 8;
7 HopfieldNetwork hopfield = new HopfieldNetwork(SIZE);
8 Console.WriteLine("原始权值为:");
9 Console.WriteLine(hopfield.weight.toMatrixString(0));
10 //以下为2个模式
11 bool[] sample1 = new bool[] { false, true, false, true, true, true, false, false }; //01011100
12 bool[] sample2 = new bool[] { false, false, true, true, true, true, true, true }; //00111111
13 //训练2个模式并输出训练后的权值
14 hopfield.train(sample1);
15 Console.WriteLine("训练样本01010101后权值为:");
16 Console.WriteLine(hopfield.weight.toMatrixString(0));
17 hopfield.train(sample2);
18 Console.WriteLine("训练样本0011后权值为:");
19 Console.WriteLine(hopfield.weight.toMatrixString(0));
20 string input = null;
21 bool[] pattern = new bool[SIZE];
22 bool[] result = new bool[SIZE];
23 StringBuilder sb = new StringBuilder();
24 //让用户循环输入8维向量并尝试识别
25 //结果证明,能够正确识别被训练的2个模式,而且能够识别与之相近的模式
26 while(true)
27 {
28 Console.Write("输入一个模式(能够识别01011100, 00111111),exit退出:");
29 input = Console.ReadLine();
30 if(input=="exit") break;
31 if(input.Length!=SIZE)continue;
32 for (int i = 0; i < SIZE; i++)
33 pattern[i] = (input[i] != '0');
34 result = hopfield.present(pattern);
35 sb.Clear();
36 for (int i = 0; i < SIZE; i++)
37 sb.Append(result[i] ? "1" : "0");
38 Console.WriteLine("识别结果为:"+sb.ToString());
39 }
40 }

 

the end of this article

posted @ 2010-10-17 11:53  基础软件  阅读(1760)  评论(0编辑  收藏  举报