作者:射命丸咲 Python 与 机器学习 爱好者
知乎专栏:https://zhuanlan.zhihu.com/carefree0910-pyml
个人网站:http://www.carefree0910.com
往期阅读:
从零开始学人工智能(9)--Python · 神经网络(二*)· 层
从零开始学人工智能(10)--Python · 神经网络(三*)· 网络
最终成品的 GitHub 地址:
https://github.com/carefree0910/MachineLearning/tree/master/NN
本章用到的 GitHub 地址:
https://github.com/carefree0910/MachineLearning/blob/master/Zhihu/NN/_extra/one/Networks.py
与 tensorflow 版本类似,我们要先定义一个能把输入变成输出的函数(输出函数)和一个用来训练我们模型的函数(训练函数)、然后定义一些函数评估我们的模型。由于不像 tensorflow 那样把最终损失化为了一个数、所以我们的输出函数(前向传导算法)相比之下形式很简单:
def _get_activations(self, x):
_activations = [self._layers[0].activate(
x, self._weights[0], self._bias[0])]
for i, layer in enumerate(self._layers[1:]):
_activations.append(layer.activate(
_activations[-1], self._weights[i + 1], self._bias[i + 1]))
return _activations
需要指出的是,由于 BP 算法是自己实现的、所以需要把激活值记录下来以减少 BP 算法中的计算量(因为许多激活函数【比如 Sigmoid】的导函数用函数值来算会比用输入算块一些)
训练函数的话就比 tensorflow 版本要复杂了、因为要手动进行梯度下降:
def fit(self, x=None, y=None, lr=0.01, epoch=10):
# Initialize
self._add_cost_layer()
self._init_optimizers(lr)
layer_width = len(self._layers)
# Train
for counter in range(epoch):
# 如有必要,更新优化器中的参数
self._w_optimizer.update(); self._b_optimizer.update()
# 调用前向传导算法获取各个激活值
_activations = self._get_activations(x)
# 调用反向传播算法获得各个局部梯度
_deltas = [self._layers[-1].bp_first(y, _activations[-1])]
for i in range(-1, -len(_activations), -1):
_deltas.append(self._layers[i - 1].bp(
_activations[i - 1], self._weights[i], _deltas[-1]
))
# 调用相应方法进行参数的更新
for i in range(layer_width - 2, 0, -1):
self._opt(i, _activations[i - 1], _deltas[layer_width-i-1])
self._opt(0, x, _deltas[-1])
可以看到里面用了大量 Optimizers 相关的东西,若有需要的话可以参见这篇文章(地址:http://www.carefree0910.com/posts/55a23cf0/);这里我们只需知道 self._opt 这个函数能够利用激活值和梯度帮我们更新相应的变量就行
可能会有观众老爷注意到我在定义 _deltas 这个存储梯度的列表时调用的是 bp_first 函数,这是什么意思呢?不知大家还记不记得、在 BP 算法推导过程中、最后一层(亦即 CostLayer)的梯度计算和其余层是不太一样的,这里这个 bp_first 即是 CostLayer 对应的 BP 算法
模型搭好之后就能跑一跑并评估一下了。我写了一个小的可视化函数并生成了一个螺旋线数据来进行测试和评估,效果大概如下:
模型结构是两层 ReLU 各 24 个神经元,CostLayer 是 Softmax + Log Likelihood,Optimizers 选择的是 Adam。迭代了 1000 次,耗时 1 秒左右。值得一提的是,用 tensorflow 来训练的话要 3 秒左右(GPU 版本),观众老爷可以想想这是为什么 ( σ'ω')σ (事实上,tensorflow 本身不适合用于训练规模太小的模型、不仅限于这一种情况)
以上,一个完整的纯 Numpy 实现的神经网络结构就搭建完了,合共 150 行 Python 代码,比 tensorflow 版本的要长一些
希望观众老爷们能够喜欢~
公众号后台回复关键词学习
回复 人工智能 揭开人工智能的神秘面纱
回复 贝叶斯算法 贝叶斯算法与新闻分类
回复 机器学习 R&Python机器学习
回复 阿里数据 阿里数据系列课程
回复 Python Python机器学习案例实战
回复 Spark 征服Spark第一季
回复 kaggle 机器学习kaggle案例
回复 大数据 大数据系列视频
回复 数据分析 数据分析人员的转型
回复 数据挖掘 数据挖掘与人工智能
回复 机器学习 R&Python机器学习
回复 阿里数据 阿里数据系列课程
回复 R R&Python机器学习入门