【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 網路,用它作聯想記憶時,首先通過一個學習訓練的過程確定網路中的權係數,使所記憶的資訊在網路的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神經網路的數字識別