Python实现RNN
一般的前馈神经网络中, 输出的结果只与当前输入有关与历史状态无关, 而递归神经网络(Recurrent Neural Network, RNN)神经元的历史输出参与下一次预测.
本文中我们将尝试使用RNN处理二进制加法问题: 两个加数作为两个序列输入, 从右向左处理加数序列.和的某一位不仅与加数的当前位有关, 还与上一位的进位有关.
词语的含义与上下文有关, 未来的状态不仅与当前相关还与历史状态相关. 因为这种性质, RNN非常适合自然语言处理和时间序列分析等任务.
RNN与前馈神经网络最大的不同在于多了一条反馈回路, 将RNN展开即可得到前馈神经网络.
RNN同样采用BP算法进行训练, 误差反向传播时需要逆向通过反馈回路.
定义输出层误差为:
\]
其中, \(O_j\)是预测输出, \(T_j\)是参考输出.
因为隐含层没有参考输出, 采用下一层的误差加权和代替\(T_j - O_j\). 对于隐含层神经元而言这里的下一层可能是输出层, 也可能是其自身.
更多关于BP算法的内容可以参考BP神经网络与Python实现
定义RNN结构
完整的代码可以在rnn.py找到.
因为篇幅原因, 相关工具函数请在完整源码中查看, 文中不再赘述.
这里我们定义一个简单的3层递归神经网络, 隐含层神经元的输出只与当前状态以及上一个状态有关.
定义RNN
类:
class RNN:
def __init__(self):
self.input_n = 0
self.hidden_n = 0
self.output_n = 0
self.input_weights = [] # (input, hidden)
self.output_weights = [] # (hidden, output)
self.hidden_weights = [] # (hidden, hidden)
def setup(self, ni, nh, no):
self.input_n = ni
self.hidden_n = nh
self.output_n = no
self.input_weights = make_rand_mat(self.input_n, self.hidden_n)
self.output_weights = make_rand_mat(self.hidden_n, self.output_n)
self.hidden_weights = make_rand_mat(self.hidden_n, self.hidden_n)
这里定义了几个比较重要的矩阵:
input_weights
: 输入层和隐含层之间的连接权值矩阵.output_weights
: 隐含层和输出层之间的连接权值矩阵hidden_weights
: 隐含层反馈回路权值矩阵, 反馈回路从一个隐含层神经元出发到另一个隐含层神经元.
因为本文的RNN只有一阶反馈, 因此只需要一个反馈回路权值矩阵.对于n阶RNN来说需要n个反馈权值矩阵.
定义test()
方法作为示例代码的入口:
def test(self):
self.setup(2, 16, 1)
for i in range(20000):
a_int = int(rand(0, 127))
a = int_to_bin(a_int, dim=8)
a = np.array([int(t) for t in a])
b_int = int(rand(0, 127))
b = int_to_bin(b_int, dim=8)
b = np.array([int(t) for t in b])
c_int = a_int + b_int
c = int_to_bin(c_int, dim=8)
c = np.array([int(t) for t in c])
guess, error = self.do_train([a, b], c, dim=8)
if i % 1000 == 0:
print("Predict:" + str(guess))
print("True:" + str(c))
print("Error:" + str(error))
out = 0
for index, x in enumerate(reversed(guess)):
out += x * pow(2, index)
print str(a_int) + " + " + str(b_int) + " = " + str(out)
result = str(self.predict([a, b], dim=8))
print(result)
print "==============="
do_train
方法仅进行一次训练, 这里我们生成了20000组训练数据每组数据仅执行一次训练.
predict方法
predict
方法执行一次前馈过程, 以给出预测输出序列.
def predict(self, case, dim=0):
guess = np.zeros(dim)
hidden_layer_history = [np.zeros(self.hidden_n)]
for i in range(dim):
x = np.array([[c[dim - i - 1] for c in case]])
hidden_layer = sigmoid(np.dot(x, self.input_weights) + np.dot(hidden_layer_history[-1], self.hidden_weights))
output_layer = sigmoid(np.dot(hidden_layer, self.output_weights))
guess[dim - i - 1] = np.round(output_layer[0][0]) # if you don't like int, change it
hidden_layer_history.append(copy.deepcopy(hidden_layer))
初始化guess
向量作为预测输出, hidden_layer_history
列表保存隐含层的历史值用于计算反馈的影响.
自右向左遍历序列, 对每个元素进行一次前馈.
hidden_layer = sigmoid(np.dot(x, self.input_weights) + np.dot(hidden_layer_history[-1], self.hidden_weights))
上面这行代码是前馈的核心, 隐含层的输入由两部分组成:
来自输入层的输入
np.dot(x, self.input_weights)
.来自上一个状态的反馈
np.dot(hidden_layer_history[-1], self.hidden_weights)
.
output_layer = sigmoid(np.dot(hidden_layer, self.output_weights))
guess[dim - position - 1] = np.round(output_layer[0][0])
上面这行代码执行输出层的计算, 因为二进制加法的原因这里对输出结果进行了取整.
train方法
定义train
方法来控制迭代过程:
def train(self, cases, labels, dim=0, learn=0.1, limit=1000):
for i in range(limit):
for j in range(len(cases)):
case = cases[j]
label = labels[j]
self.do_train(case, label, dim=dim, learn=learn)
do_train
方法实现了具体的训练逻辑:
def do_train(self, case, label, dim=0, learn=0.1):
input_updates = np.zeros_like(self.input_weights)
output_updates = np.zeros_like(self.output_weights)
hidden_updates = np.zeros_like(self.hidden_weights)
guess = np.zeros_like(label)
error = 0
output_deltas = []
hidden_layer_history = [np.zeros(self.hidden_n)]
for i in range(dim):
x = np.array([[c[dim - i - 1] for c in case]])
y = np.array([[label[dim - i - 1]]]).T
hidden_layer = sigmoid(np.dot(x, self.input_weights) + np.dot(hidden_layer_history[-1], self.hidden_weights))
output_layer = sigmoid(np.dot(hidden_layer, self.output_weights))
output_error = y - output_layer
output_deltas.append(output_error * sigmoid_derivative(output_layer))
error += np.abs(output_error[0])
guess[dim - i - 1] = np.round(output_layer[0][0])
hidden_layer_history.append(copy.deepcopy(hidden_layer))
future_hidden_layer_delta = np.zeros(self.hidden_n)
for i in range(dim):
x = np.array([[c[i] for c in case]])
hidden_layer = hidden_layer_history[-i - 1]
prev_hidden_layer = hidden_layer_history[-i - 2]
output_delta = output_deltas[-i - 1]
hidden_delta = (future_hidden_layer_delta.dot(self.hidden_weights.T) +
output_delta.dot(self.output_weights.T)) * sigmoid_derivative(hidden_layer)
output_updates += np.atleast_2d(hidden_layer).T.dot(output_delta)
hidden_updates += np.atleast_2d(prev_hidden_layer).T.dot(hidden_delta)
input_updates += x.T.dot(hidden_delta)
future_hidden_layer_delta = hidden_delta
self.input_weights += input_updates * learn
self.output_weights += output_updates * learn
self.hidden_weights += hidden_updates * learn
return guess, error
训练逻辑中两次遍历序列, 第一次遍历执行前馈过程并计算输出层误差.
第二次遍历计算隐含层误差, 下列代码是计算隐含层误差的核心:
hidden_delta = (future_hidden_layer_delta.dot(self.hidden_weights.T) +
output_delta.dot(self.output_weights.T)) * sigmoid_derivative(hidden_layer)
因为隐含层在前馈过程中参与了两次, 所以会有两层神经元反向传播误差:
- 输出层传递的误差加权和
output_delta.dot(self.output_weights.T)
- 反馈回路中下一层隐含神经元传递的误差加权和
future_hidden_layer_delta.dot(self.hidden_weights.T)
将两部分误差求和然后乘自身输出的sigmoid导数sigmoid_derivative(hidden_layer)
即为隐含层误差, 这里与普通前馈网络中的BP算法是一致的.
测试结果
执行test()
方法可以看到测试结果:
Predict:[1 0 0 0 1 0 1 0]
True:[1 0 0 0 1 0 1 0]
123 + 15 = 138
===============
Error:[ 0.22207356]
Predict:[1 0 0 0 1 1 1 1]
True:[1 0 0 0 1 1 1 1]
72 + 71 = 143
===============
Error:[ 0.3532948]
Predict:[1 1 0 1 0 1 0 0]
True:[1 1 0 1 0 1 0 0]
118 + 94 = 212
===============
Error:[ 0.35634191]
Predict:[0 1 0 0 0 0 0 0]
True:[0 1 0 0 0 0 0 0]
41 + 23 = 64
预测精度还是很令人满意的.
Python实现RNN的更多相关文章
- Windows64 系统下Python、NumPy与matplotlib 安装方法
今下午想用Python跑RNN网络,结果代码在导入包numpy时并没有报错,但是在用里面的函数时报错,因小编也是新手,只学习了Python的基础语法,并没有使用过第三方包,安装了一下午还没弄好,本以为 ...
- tensorflow dynamic rnn源码分析
python3.6,tensorflow1.11 测试代码: tensorflow在eager模式下进行测试,方便调试,查看中间结果 import tensorflow as tf tf.enable ...
- Caffe、TensorFlow、MXnet三个开源库对比
库名称 开发语言 支持接口 安装难度(ubuntu) 文档风格 示例 支持模型 上手难易 Caffe c++/cuda c++/python/matlab *** * *** CNN ** MXNet ...
- Caffe、TensorFlow、MXnet三个开源库对比+主流分类模型对比
库名称 开发语言 支持接口 安装难度(ubuntu) 文档风格 示例 支持模型 上手难易 Caffe c++/cuda c++/python/matlab *** * *** CNN ** MXNet ...
- tensorflow代码中的一个bug
tensorflow-gpu版本号 pip show tensorflow-gpu Name: tensorflow-gpu Version: 1.11.0 Summary: TensorFlow i ...
- tensorflow BasicRNNCell调试
运行以下代码,进入~/anaconda3/lib/python3.5/site-packages/tensorflow/python/ops/rnn.py和~/anaconda3/lib/python ...
- Tensorflow.nn 核心模块详解
看过前面的例子,会发现实现深度神经网络需要使用 tensorflow.nn 这个核心模块.我们通过源码来一探究竟. # Copyright 2015 Google Inc. All Rights Re ...
- Recurrent Neural Network系列2--利用Python,Theano实现RNN
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...
- IMPLEMENTING A GRU/LSTM RNN WITH PYTHON AND THEANO - 学习笔记
catalogue . 引言 . LSTM NETWORKS . LSTM 的变体 . GRUs (Gated Recurrent Units) . IMPLEMENTATION GRUs 0. 引言 ...
随机推荐
- java学习笔记 --- 数组
一.Java的内存分配 A:栈内存: 存储局部变量,只要是在方法中定义的变量都是局部变量.一旦变量的生命周期结束该变量就被释放. B:堆内存: 存储所有new出来的,及实体(对象),每一个实体 ...
- 自己开发图表插件,脱离echart
前言 由于公司业务需要做一些图标来展示一些数据,之前都是用百度的echart.js.这次放弃使用它转而自己开发是有几个原因1.echart文件太大,有些功能用不到2.echart样式不易扩展3.需求简 ...
- 译:Missing index DMV的 bug可能会使你失去理智---慎重看待缺失索引DMV中的信息
注: 本文译自https://www.sqlskills.com/blogs/paul/missing-index-dmvs-bug-that-could-cost-your-sanity/ 原文作者 ...
- Zookeeper3.4.9分布式集群安装
一.依赖文件安装 1.1 JDK 参见博文:http://www.cnblogs.com/liugh/p/6623530.html 二.文件准备 2.1 文件名称 zookeeper-3.4.9.ta ...
- sleep()和wait()的区别 --- 快入睡了,突然想起一个知识点,搞完就睡
自从开了博客之后,大部分是转发的,不断的ctrl+c和ctrl+v,知识是越屯越多,吸收的却很少,后来越来越懒,直接保存链接了. 我已经认识到了自己的错误,自己查询到的这些知识,以后还是会定期保存的, ...
- Angular2入门-数据绑定
▓▓▓▓▓▓ 大致介绍 Angular2中数据绑定的方式默认是以单向方式,数据绑定的方式可以分为: 1.属性绑定和插值表达式 组件类-> 模板 2.事件绑定:模板 -> 组件类 3.双向绑 ...
- python黑魔法之metaclass
最近了解了一下python的metaclass,在学习的过程中,把自己对metaclass的理解写出来和大家分享. 首先, metaclass 中文叫元类,这个元类怎么来理解呢.我们知道,在Pytho ...
- Webpack模块加载器
一.介绍 Webpack是德国开发者 Tobias Koppers 开发的模块加载器,它能把所有的资源文件(JS.JSX.CSS.CoffeeScript.Less.Sass.Image等)都作为模块 ...
- 第八章 Hibernate数据操作技巧
第八章 Hibernate数据操作技巧8.1 分组统计数据 语法:[select]... from ...[where] [group by...[having...]] [order by ...
- Go语言及Web框架Beego环境
Go语言及Web框架Beego环境无脑搭建 [原]Go语言及Web框架Beego环境无脑搭建 本文涉及软件均以截至到2013年10月12日的最新版本为准 1. 相关软件准备: 1) go1.2rc1. ...