该neuralnetwork类的代码:
class neuralNetwork:
# 初始化神经网络,构造函数
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
# 设置每个输入、隐藏、输出层中的节点数
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
# 链接权重矩阵,wih和who
# weights inside the arrays are w_i_j, where link is from node i to node j in the next layer
# w11 w21
# w12 w22 etc
self.wih = np.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes)) # 正态分布函数
self.who = np.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))
# 学习率
self.lr = learningrate
# 创建激活函数(函数的另一种定义方法,这样以后可以直接调用)
self.activation_function = lambda x: S.expit(x)
pass
# 训练神经网络
def train(self, inputs_list, targets_list):
# 将输入列表转换成二维数组
inputs = np.array(inputs_list, ndmin=2).T
targets = np.array(targets_list, ndmin=2).T
# 将输入信号计算到隐藏层
hidden_inputs = np.dot(self.wih, inputs)
# 计算隐藏层中输出的信号(使用激活函数计算)
hidden_outputs = self.activation_function(hidden_inputs)
# 将传输的信号计算到输出层
final_inputs = np.dot(self.who, hidden_outputs)
# 计算输出层中输出的信号(使用激活函数)
final_outputs = self.activation_function(final_inputs)
# 计算输出层的误差:(target - actual)(预期目标输出值-实际计算得到的输出值)
output_errors = targets - final_outputs
# 隐藏层的误差:是输出层误差按权重分割,在隐藏节点上重新组合
hidden_errors = np.dot(self.who.T, output_errors)
# 反向传播,更新各层权重
# 更新隐层和输出层之间的权重
self.who += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)),
np.transpose(hidden_outputs))
# 更新输入层和隐藏层之间的权重
self.wih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))
# pass一般用于占位置,定义一个空函数程序会报错,当没有想好函数的内容可以用pass填充,使得程序正常运行
pass
# 查询神经网络:接受神经网络的输入,返回神经网络的输出
def query(self, inputs_list):
# 将输入列表转换成二维数组
inputs = np.array(inputs_list, ndmin=2).T
# 将输入信号计算到隐藏层
hidden_inputs = np.dot(self.wih, inputs)
# 将信号从隐藏层输出
hidden_outputs = self.activation_function(hidden_inputs)
# 将信号引入到输出层
final_inputs = np.dot(self.who, hidden_outputs)
# 将信号从输出层输出
final_outputs = self.activation_function(final_inputs)
# 返回输出层的输出值
return final_outputs
代码解释:
1.
np.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
正态分布函数实现初始化
numpy.random.normal(loc=0.0, scale=1.0, size=None)
参数的意义为:
loc:float
概率分布的均值,对应着整个分布的中心center
scale:float
概率分布的标准差,对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高
size:int or tuple of ints
输出的shape,默认为None,只输出一个值
我们更经常会用到np.random.randn(size)所谓标准正太分布(μ=0, σ=1),对应于np.random.normal(loc=0, scale=1, size)
2.
S.expit(x) :sigmod激活函数
3.
hidden_inputs = np.dot(self.wih, inputs)
矩阵点积
4.
np.ndarray.T 矩阵转置
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.T.html
5。
np.array(inputs_list, ndmin=2).T
ndmin代表结果输出最小的纬度,这里使其输出为二维数组
6.
# 更新隐层和输出层之间的权重
self.who += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)),
np.transpose(hidden_outputs))
# 更新输入层和隐藏层之间的权重
self.wih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))
这两行是BP反向传播的公式,是这个BP结构最重要的部分
。
# 设置输入、隐藏、输出层中的节点数,和学习率
input_nodes = 30
hidden_nodes = 30*2+1
output_nodes = 1
learning_rate = 0.1
# 训练神经网络
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
epochs = 400
print('begin training...')
for e in range(epochs):
# go through all records in the training data set
for i in range(80):
inputs=X[i, :]
targets=Y[i]
n.train(inputs, targets) # 开始训练
if e%100==0:
print("train", e, 'finished!')
# 开始测试
print('测试:。。。')
ans=[]
for i in range(0, 103):
inputs = X[i, :]
targets = Y[i]
ans.append(n.query(inputs))
print('ans:', np.array(ans))
# 权重层输出
print('输出权重:')
print(n.wih)
print(n.who)
epochs是训练轮数,将训练集中的每个样本都进行一遍训练算作一轮。
可以看出,该BP网络类,可以实现内部权重输出的操作,有利于对对该神经网络的黑箱性模型进行观测。