1. 程式人生 > >【Python】改進Hopfield網路程式碼實現

【Python】改進Hopfield網路程式碼實現

Hopfield網路

Hopfield網路由美國加州理工學院物理學教授J. J. Hopfield於1982年提出[1]
網路從輸出到輸入有反饋連線,在輸入的激勵下,會產生不斷的狀態變化,是一種單層反饋神經網路,也可以被視為一種迴圈神經網路
Hopfield神經網路是反饋網路中最簡單且應用廣泛的模型,它具有聯想記憶的功能,是神經網路發展歷史上的一個重要的里程碑
根據網路的輸出是離散量或是連續量,Hopfield神經網路大致分為兩種:離散Hopfield網路(Discrete Hopfield Neural Network, DHNN)和連續Hopfield網路(Continuous Hopfield Neural Network, CHNN)

網路大致結構如下圖所示:
Hopfield

離散Hopfield網路可以視為一個類腦模型,主要是因為其可用於聯想記憶,即聯想儲存器,這是類人智慧的特點之一
人類的所謂“觸景生情”就是見到一些類同於過去接觸的景物,容易產生對過去情景的回味和思憶
對於Hopfield 網路,用它作聯想記憶時,首先通過一個學習訓練的過程確定網路中的權係數,使所記憶的資訊在網路的n維超立方體的某一個頂角達到能量最小
當網路的權重矩陣確定之後,只要向網路給出輸入向量,這個向量可能是區域性資料.即不完全或部分不正確的資料,但是網路仍然能夠產生所記憶資訊的完整輸出

1984年,J. Hopfield設計並研製了網路模型的電路,併成功地解決了旅行商計算難題(TSP快速尋優問題)
現今,Hopfield網路主要在聯想和識別方面有一些應用,如帶噪聲點陣符號識別和模糊或缺失數字影象的復原等

一些更加具體的介紹、更多的公式推導及應用示例可參見Ref.[2][3][4]等

Python程式碼實現

本文所介紹的是無自反饋的且演算法改進後離散Hopfield網路
該改進演算法根據Hebb歸一化學習原則,並採用了Kronecker積的方法完成了實現(不幸的是解釋文件已丟失)
但從演算法的實測效能來看,遠勝於NeuPy、NeuroLab等模組包中的Hopfield網路方法

以下為所編寫的演算法程式碼和示例DEMO:
【Hopfield.py】

#!/usr/bin/env python
#-*- coding: utf-8 -*-

'''
Hopfield Improved Algorithm
@Author: Alex Pan
@From: CASIA
@Date: 2017.03
'''
import numpy as np ################################### Global Parameters ################################### # Data Type uintType = np.uint8 floatType = np.float32 ################################### Global Parameters ################################### # Hopfield Class class HOP(object): def __init__(self, N): # Bit Dimension self.N = N # Weight Matrix self.W = np.zeros((N, N), dtype = floatType) # Calculate Kronecker Square Product of [factor] itself OR use np.kron() def kroneckerSquareProduct(self, factor): ksProduct = np.zeros((self.N, self.N), dtype = floatType) # Calculate for i in xrange(0, self.N): ksProduct[i] = factor[i] * factor return ksProduct # Training a single stableState once a time, mainly to train [W] def trainOnce(self, inputArray): # Learn with normalization mean = float(inputArray.sum()) / inputArray.shape[0] self.W = self.W + self.kroneckerSquareProduct(inputArray - mean) / (self.N * self.N) / mean / (1 - mean) # Erase diagonal self-weight index = range(0, self.N) self.W[index, index] = 0. # Overall training function def hopTrain(self, stableStateList): # Preprocess List to Array type stableState = np.asarray(stableStateList, dtype = uintType) # Exception if np.amin(stableState) < 0 or np.amax(stableState) > 1: print 'Vector Range ERROR!' return # Train if len(stableState.shape) == 1 and stableState.shape[0] == self.N: print 'stableState count: 1' self.trainOnce(stableState) elif len(stableState.shape) == 2 and stableState.shape[1] == self.N: print 'stableState count: ' + str(stableState.shape[0]) for i in xrange(0, stableState.shape[0]): self.trainOnce(stableState[i]) else: print 'SS Dimension ERROR! Training Aborted.' return print 'Hopfield Training Complete.' # Run HOP to output def hopRun(self, inputList): # Preprocess List to Array type inputArray = np.asarray(inputList, dtype = floatType) # Exception if len(inputArray.shape) != 1 or inputArray.shape[0] != self.N: print 'Input Dimension ERROR! Runing Aborted.' return # Run matrix = np.tile(inputArray, (self.N, 1)) matrix = self.W * matrix ouputArray = matrix.sum(1) # Normalize m = float(np.amin(ouputArray)) M = float(np.amax(ouputArray)) ouputArray = (ouputArray - m) / (M - m) # Binary ''' \SWITCH/ : 1/-1 OR 1/0 ouputArray[ouputArray < 0.5] = -1. ''' # \Division/ ouputArray[ouputArray < 0.5] = 0. # ''' # \END/ ouputArray[ouputArray > 0] = 1. return np.asarray(ouputArray, dtype = uintType) # Reset HOP to initialized state def hopReset(self): # Weight Matrix RESET self.W = np.zeros((self.N, self.N), dtype = floatType) # Utility routine for printing the input vector: [NperGroup] numbers each piece def printFormat(vector, NperGroup): string = '' for index in xrange(len(vector)): if index % NperGroup == 0: ''' \SWITCH/ : Single-Row OR Multi-Row string += ' ' ''' # \Division/ string += '\n' # ''' # \END/ # ''' \SWITCH/ : Image-Matrix OR Raw-String if str(vector[index]) == '0': string += ' ' elif str(vector[index]) == '1': string += '*' else: string += str(vector[index]) ''' # \Division/ string += str(vector[index]) # ''' # \END/ string += '\n' print string # DEMO of Hopfield Net def HOP_demo(): zero = [0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0] one = [0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0] two = [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1] hop = HOP(5 * 6) hop.hopTrain([zero, one, two]) half_zero = [0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] print 'Half-Zero:' printFormat(half_zero, 5) result = hop.hopRun(half_zero) print 'Recovered:' printFormat(result, 5) half_two = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1] print 'Half-Two:' printFormat(half_two, 5) result = hop.hopRun(half_two) print 'Recovered:' printFormat(result, 5) half_two = [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] print 'Another Half-Two:' printFormat(half_two, 5) result = hop.hopRun(half_two) print 'Recovered:' printFormat(result, 5) ########################## if __name__ == '__main__': HOP_demo()

Reference


[1] J. J. Hopfield, “Neural networks and physical systems with emergent collective computational abilities”, Proceedings of the National Academy of Sciences of the USA, vol. 79 no. 8 pp. 2554–2558, April 1982
[2] Hopfield network - Wikipedia
[3] Hopfield模型
[4] 基於Hopfield神經網路的數字識別