目标:推导、实现一个简单的人工神经网络
结点激活函数使用
初始连接权重可以随机生成
信号传播
为了实现信号传播,要将上一层各结点的输出信号按该结点每条输出连接的权重比例进行分配,并在该层各结点处得到所有输入连接的组合信号,对组合信号应用激活函数就可以得到结点的实际输出信号。
以Input层和Hidden层的信号传播为例,设Input层各结点输入信号构成的矩阵为,
由于对Input层输入信号并不应用激活函数,所以Input层输出信号与其输入信号相等。而Input层到Hidden层的连接权重矩阵为,
其中是指Input层结点到Hidden层结点的连接权重。由此得到Hidden层各结点组合输入信号(输入信号总和),并对其应用激活函数,就是Hidden层各结点输出信号,
同理可得Hidden层与Output层的信号传播方法,
误差反向传播
以Hidden层和Output层的误差反向传播为例,由训练数据的目标值和Output层的实际输出值可以得到Output层的误差矩阵,
将误差按原始权重比例分配到每条连接并反向传播至Hidden层,分配到各条连接上的误差和Hidden层的误差分别为
其中是指Hidden层结点到Output层结点连接分配到的误差,转化为矩阵表述,,是将原权重比例矩阵去归一化因子后的得到的矩阵。
改进连接权重
通过梯度下降法使用误差指导连接权重的调整。Output层结点误差总和关于输入连接权重的函数关系为,
转化为对单个结点进行运算,求出误差在各权重维度上的梯度,
结合学习率,即可得到权重的改变量
代码实现
import numpy as np
import scipy.special
class neuralNetwork :
#构造函数 设定输入层、隐藏层、输出层节点数量
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
self.nInodes=inputnodes
self.nHnodes=hiddennodes
self.nOnodes=outputnodes
self.fLrate =learningrate
self.mW_ih=np.random.normal(0,pow(self.nHnodes,-0.5),(self.nHnodes,self.nInodes))
self.mW_ho=np.random.normal(0,pow(self.nOnodes,-0.5),(self.nOnodes,self.nHnodes))
self.activation_function=lambda x: scipy.special.expit(x)
#学习训练集数据 优化权重
def train(self,inputs_list,targets_list):
mO_t=np.array(targets_list,ndmin=2).T
#mO_o=self.query(inputs_list)
#-------------------------------------------------------------#
mX_i=np.array(inputs_list,ndmin=2).T
mX_h=np.dot(self.mW_ih,mX_i)
mO_h=self.activation_function(mX_h)
mX_o=np.dot(self.mW_ho,mO_h)
mO_o=self.activation_function(mX_o)
#-------------------------------------------------------------#
mE_o=mO_t-mO_o
mE_h=np.dot(self.mW_ho.T,mE_o)
self.mW_ho+=self.fLrate*np.dot((mE_o*mO_o*(1-mO_o)),mO_h.T)
self.mW_ih+=self.fLrate*np.dot((mE_h*mO_h*(1-mO_h)),mX_i.T)
#给定输入 从输出节点给出答案
def query(self,inputs_list):
mX_i=np.array(inputs_list,ndmin=2).T
mX_h=np.dot(self.mW_ih,mX_i)
mO_h=self.activation_function(mX_h)
mX_o=np.dot(self.mW_ho,mO_h)
mO_o=self.activation_function(mX_o)
return mO_o