Hopfield神经网络及C#实现

最近在看一本书, 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网络测试代码
/// <summary>
/// 由8个神经元组成简单的Hopfield网络,识别简单的模式
/// </summary>
public void simplePattern()
{
    const int SIZE = 8;
    HopfieldNetwork hopfield = new HopfieldNetwork(SIZE);
    Console.WriteLine(“原始权值为:”);
    Console.WriteLine(hopfield.weight.toMatrixString(0));
    //以下为2个模式
    bool[] sample1 = new bool[] { false, true, false, true, true, true, false, false };  //01011100
    bool[] sample2 = new bool[] { false, false, true, true, true, true, true, true };  //00111111
    //训练2个模式并输出训练后的权值
    hopfield.train(sample1);
    Console.WriteLine(“训练样本01010101后权值为:”);
    Console.WriteLine(hopfield.weight.toMatrixString(0));
    hopfield.train(sample2);
    Console.WriteLine(“训练样本0011后权值为:”);
    Console.WriteLine(hopfield.weight.toMatrixString(0));
    string input = null;
    bool[] pattern = new bool[SIZE];
    bool[] result = new bool[SIZE];
    StringBuilder sb = new StringBuilder();
    //让用户循环输入8维向量并尝试识别
    //结果证明,能够正确识别被训练的2个模式,而且能够识别与之相近的模式
    while(true)
    {
        Console.Write(“输入一个模式(能够识别01011100, 00111111),exit退出:”);
        input = Console.ReadLine();
        if(input==”exit”) break;
        if(input.Length!=SIZE)continue;
        for (int i = 0; i < SIZE; i++)               
            pattern[i] = (input[i] != ‘0’);
        result = hopfield.present(pattern);
        sb.Clear();
        for (int i = 0; i < SIZE; i++)               
            sb.Append(result[i] ? “1” : “0”);               
        Console.WriteLine(“识别结果为:”+sb.ToString());
    }           
}

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

来源:http://www.cnblogs.com/FoundationSoft/archive/2010/10/17/1853530.html

About 智足者富

http://chenpeng.info

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>