【1】引言
前序学习进程中,对霍普菲尔德神经网络有了初步认识,使用Hebbian方法测试了霍普菲尔德神经网络算法。相关学习文章链接为:
在此基础上,尝试探索使用Storkey方法对霍普菲尔德神经网络算法进行测试。
【2】代码测试
和Hebbian训练方法一样,Storkey训练方法需要提前完成准备工作,定义子函数和主函数,完成实际效果测试。
【2.1】准备工作
准备工作需要引入必要模块:
python
import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入nmatplotlib模块
【2.2】主函数
主函数通过把算法实施过程拆解为调用不同的子函数,直观表达了程序运行框架。
python
# 示例:创建一些简单的模式
patterns = [
np.array([1, 1, 1, -1, -1, -1]),
np.array([-1, -1, -1, 1, 1, 1])
]
# 初始化权重
# 获得patterns第一个元素,也就是np.array([1, 1, 1, -1, -1, -1])中数字的数量
n_neurons = len(patterns[0])
weights = initialize_weights(n_neurons)
# 训练网络
weights = train(weights, patterns)
# 测试回忆功能
initial_state = np.array([1, 1, 1, -1, -1, -1])
recalled_pattern = recall(weights, initial_state)
# 可视化结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(initial_state.reshape(1, -1), cmap='gray')
plt.title('Initial State')
plt.subplot(1, 3, 2)
plt.imshow(recalled_pattern.reshape(1, -1), cmap='BuGn')
plt.title('Recalled Pattern')
plt.subplot(1, 3, 3)
plt.imshow(patterns[0].reshape(1, -1), cmap='Blues')
plt.title('Original Pattern')
plt.show()
主函数直接调用了initialize_weights()、train()和recall()三个子函数,它们分别执行权重初始化、模型训练和测试回忆功能,下一步即可对这些子函数进行学习。
【2.3】子函数
【2.3.1】initialize_weights()函数
python
# 定义初始化函数
def initialize_weights(n_neurons):
"""
初始化霍普菲尔德网络的权重矩阵
:param n_neurons: 神经元的数量
:return: 初始的权重矩阵
"""
# 返回一个(n_neurons行, n_neurons列)纯0矩阵
return np.zeros((n_neurons, n_neurons))
initialize_weights()函数生成的是 (n_neurons行, n_neurons列)纯0矩阵,作为权重weights的初始值。
【2.3.2】train()函数
python
# 训练模型传入的参数有weights和patterns
def train(weights, patterns):
"""
使用 Storkey 学习规则训练网络
:param weights: 权重矩阵
:param patterns: 训练模式的列表
:return: 训练后的权重矩阵
"""
for pattern in patterns:
# 将pattern转化为列向量
# 由于每个pattern中有n_neurons个元素,所以pattern转化后的列向量有n_neurons行
pattern = pattern.reshape(-1, 1)
# n获取pattern向量的行数,n=n_neurons
n = len(pattern)
for i in range(n):
for j in range(n):
if i != j:
# 让不同的pattern元素彼此相乘
term1 = pattern[i] * pattern[j]
# 初始值赋值0
term2 = 0
# 初始值赋值0
term3 = 0
for k in range(n):
if k != i and k != j:
# weights矩阵的结构是(n_neurons行,n_neurons列)
# term2考虑了第k和第j个pattern元素对i行k列权重的影响
term2 += weights[i, k] * pattern[k] * pattern[j]
# term3考虑了第k和第j个pattern元素对j行k列权重的影响
term3 += weights[j, k] * pattern[k] * pattern[i]
# 3个term进行了综合
delta_w = term1 - term2 - term3
# 确保 delta_w 是标量
weights[i, j] += delta_w.item()
# 确保对角线元素为 0
np.fill_diagonal(weights, 0)
# 除以总模数,进行归一化操作
weights /= len(patterns)
return weights
Storkey方法的train()函数和Hebbian方法有显著不同,Storkey方法获得weights的过程更为复杂,考虑了综合影响。
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Hebbian方法 | Storkey方法 |
| # 训练模型传入的参数有weights和patterns def train(weights, patterns): """ 使用 Hebbian 学习规则训练网络 :param weights: 权重矩阵 :param patterns: 训练模式的列表 :return: 训练后的权重矩阵 """ for pattern in patterns: # 将pattern转化为一个列向量 pattern = pattern.reshape(-1, 1) # weights是在自身的基础上叠加pattern自身的平方 weights += np.dot(pattern, pattern.T) # 确保对角线元素为 0 # 通过内置函数,让weights处于对角线上的元素都为0 np.fill_diagonal(weights, 0) # 除以总模数,进行归一化操作 weights /= len(patterns) return weights | # 训练模型传入的参数有weights和patterns def train(weights, patterns): """ 使用 Storkey 学习规则训练网络 :param weights: 权重矩阵 :param patterns: 训练模式的列表 :return: 训练后的权重矩阵 """ for pattern in patterns: # 将pattern转化为列向量 # 由于每个pattern中有n_neurons个元素,所以pattern转化后的列向量有n_neurons行 pattern = pattern.reshape(-1, 1) # n获取pattern向量的行数,n=n_neurons n = len(pattern) for i in range(n): for j in range(n): if i != j: # 让不同的pattern元素彼此相乘 term1 = pattern[i] * pattern[j] # 初始值赋值0 term2 = 0 # 初始值赋值0 term3 = 0 for k in range(n): if k != i and k != j: # weights矩阵的结构是(n_neurons行,n_neurons列) # term2考虑了第k和第j个pattern元素对i行k列权重的影响 term2 += weights[i, k] * pattern[k] * pattern[j] # term3考虑了第k和第j个pattern元素对j行k列权重的影响 term3 += weights[j, k] * pattern[k] * pattern[i] # 3个term进行了综合 delta_w = term1 - term2 - term3 # 确保 delta_w 是标量 weights[i, j] += delta_w.item() # 确保对角线元素为 0 np.fill_diagonal(weights, 0) # 除以总模数,进行归一化操作 weights /= len(patterns) return weights |
Storkey方法相对Hebbian方法,更多地考虑了交叉影响。
【2.3.3】recall()函数
python
def recall(weights, initial_state, max_iterations=100):
"""
从初始状态回忆模式
:param weights: 权重矩阵
:param initial_state: 初始状态
:param max_iterations: 最大迭代次数
:return: 回忆出的模式
"""
state = initial_state.copy()
for _ in range(max_iterations):
new_state = update(weights, state)
if np.array_equal(new_state, state):
break
state = new_state
return state
recall()函数要求调用update()函数生成新状态,用新状态来覆盖旧状态。
【2.3.4】update()函数
python
def update(weights, state):
"""
更新网络状态
:param weights: 权重矩阵
:param state: 当前网络状态
:return: 更新后的网络状态
"""
# state转化为列向量
state = state.reshape(-1, 1)
# 先用weights和state矩阵相乘,然后用np.sign()函数返回1,-1和0
# np.sign()函数,参数为正返回1,参数为负返回-1,参数为0返回0
new_state = np.sign(np.dot(weights, state))
return new_state.flatten()

++图1 Storkey训练效果++
此时的完整代码为:
python
import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入nmatplotlib模块
# 定义初始化函数
def initialize_weights(n_neurons):
"""
初始化霍普菲尔德网络的权重矩阵
:param n_neurons: 神经元的数量
:return: 初始的权重矩阵
"""
# 返回一个(n_neurons行, n_neurons列)纯0矩阵
return np.zeros((n_neurons, n_neurons))
# 训练模型传入的参数有weights和patterns
def train(weights, patterns):
"""
使用 Storkey 学习规则训练网络
:param weights: 权重矩阵
:param patterns: 训练模式的列表
:return: 训练后的权重矩阵
"""
for pattern in patterns:
# 将pattern转化为列向量
# 由于每个pattern中有n_neurons个元素,所以pattern转化后的列向量有n_neurons行
pattern = pattern.reshape(-1, 1)
# n获取pattern向量的行数,n=n_neurons
n = len(pattern)
for i in range(n):
for j in range(n):
if i != j:
# 让不同的pattern元素彼此相乘
term1 = pattern[i] * pattern[j]
# 初始值赋值0
term2 = 0
# 初始值赋值0
term3 = 0
for k in range(n):
if k != i and k != j:
# weights矩阵的结构是(n_neurons行,n_neurons列)
# term2考虑了第k和第j个pattern元素对i行k列权重的影响
term2 += weights[i, k] * pattern[k] * pattern[j]
# term3考虑了第k和第j个pattern元素对j行k列权重的影响
term3 += weights[j, k] * pattern[k] * pattern[i]
# 3个term进行了综合
delta_w = term1 - term2 - term3
# 确保 delta_w 是标量
weights[i, j] += delta_w.item()
# 确保对角线元素为 0
np.fill_diagonal(weights, 0)
# 除以总模数,进行归一化操作
weights /= len(patterns)
return weights
def update(weights, state):
"""
更新网络状态
:param weights: 权重矩阵
:param state: 当前网络状态
:return: 更新后的网络状态
"""
# state转化为列向量
state = state.reshape(-1, 1)
# 先用weights和state矩阵相乘,然后用np.sign()函数返回1,-1和0
# np.sign()函数,参数为正返回1,参数为负返回-1,参数为0返回0
new_state = np.sign(np.dot(weights, state))
return new_state.flatten()
def recall(weights, initial_state, max_iterations=100):
"""
从初始状态回忆模式
:param weights: 权重矩阵
:param initial_state: 初始状态
:param max_iterations: 最大迭代次数
:return: 回忆出的模式
"""
state = initial_state.copy()
for _ in range(max_iterations):
new_state = update(weights, state)
if np.array_equal(new_state, state):
break
state = new_state
return state
# 示例:创建一些简单的模式
patterns = [
np.array([1, 1, 1, -1, -1, -1]),
np.array([-1, -1, -1, 1, 1, 1])
]
# 初始化权重
# 获得patterns第一个元素,也就是np.array([1, 1, 1, -1, -1, -1])中数字的数量
n_neurons = len(patterns[0])
weights = initialize_weights(n_neurons)
# 训练网络
weights = train(weights, patterns)
# 测试回忆功能
initial_state = np.array([1, 1, 1, -1, -1, -1])
recalled_pattern = recall(weights, initial_state)
# 可视化结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(initial_state.reshape(1, -1), cmap='gray')
plt.title('Initial State')
plt.subplot(1, 3, 2)
plt.imshow(recalled_pattern.reshape(1, -1), cmap='BuGn')
plt.title('Recalled Pattern')
plt.subplot(1, 3, 3)
plt.imshow(patterns[0].reshape(1, -1), cmap='Blues')
plt.title('Original Pattern')
plt.show()
【3】分析
Storkey训练方法考察的关联影响更为丰富,但是记得运行效果显示:recall pattern并且和origin pattern保持完全一致。所以,实际的训练过程还未达到最佳效果。
【4】细节说明
Storkey训练方法相对于Hebbian训练方法知识train()函数发生变化。
回执图像时,因为initial_state和patterns[0]一致,所以对比图像origin pattern选择了patterns[0]。
【5】总结
探索了霍普菲尔德神经网络的基本知识,基于python语言,调用Storkey方法对霍普菲尔德神经网络算法进行了初步训练和测试。