作者:李小文,先后从事过数据分析、数据挖掘工作,主要开发语言是Python,现任一家小型互联网公司的算法工程师。
Github: https://github.com/tushushu
1. 原理篇
我们用人话而不是大段的数学公式来讲讲全连接神经网络是怎么一回事。
1.1 网络结构
灵魂画师用PPT画个粗糙的网络结构图如下:
1.2 Simoid函数
Sigmoid函数的表达式是:
不难得出:
所以,Sigmoid函数的值域是(0, 1),导数为y * (1 - y)
1.3 链式求导
z = f(y)y = g(x)
dz / dy = f'(y)dy / dx = g'(x)
dz / dz = dz / dy * dy / dx = f'(y) * g'(x)
1.4 向前传播
将当前节点的所有输入执行当前节点的计算,作为当前节点的输出节点的输入。
1.5 反向传播
将当前节点的输出节点对当前节点的梯度损失,乘以当前节点对输入节点的偏导数,作为当前节点的输入节点的梯度损失。
1.6 拓扑排序
假设我们的神经网络中有k个节点,任意一个节点都有可能有多个输入,需要考虑节点执行的先后顺序,原则就是当前节点的输入节点全部执行之后,才可以执行当前节点。
2. 实现篇
本人用全宇宙最简单的编程语言——Python实现了全连接神经网络,便于学习和使用。简单说明一下实现过程,更详细的注释请参考本人github上的代码。
2.1 创建BaseNode抽象类
将BaseNode作为各种类型Node的父类。包括如下属性:
name -- 节点名称
value -- 节点数据
inbound_nodes -- 输入节点
outbound_nodes -- 输出节点
gradients -- 对于输入节点的梯度
class BaseNode(ABC):
def __init__(self, *inbound_nodes, name=None):
self.name = name
self._value = None
self.inbound_nodes = [x for x in inbound_nodes]
self.outbound_nodes = []
self.gradients = dict()
for node in self.inbound_nodes:
node.outbound_nodes.append(self)
def __str__(self):
size = str(self.value.shape) if self.value is not None else "null"
return "" % (self.name, size)
@property
def value(self)->ndarray:
return self._value
@value.setter
def value(self, value):
err_msg = "'value' has to be a number or a numpy array!"
assert isinstance(value, (ndarray, int, float)), err_msg
self._value = value
@abstractmethod
def forward(self):
return