本节是自动求导框架技术的最后一节,本系列其余文章包括
在本节,我将会展示如何使用前面介绍的自动求导框架构建一个简单的 RNN(循环神经网络),用该神经网络来学习二进制加法。循环神经网络的相关知识可以参考这篇文章:详解循环神经网络
1. RNN简介
循环神经网络是一种处理序列的神经网络,这种网络的结构为:
将 RNN 的循环展开得到上图的右半部分,每次循环看做一个阶段。可以看出,RNN 中的隐藏层和输出层可以获取到序列当前元素前的多个元素。而每个阶段之间的参数 U,V,W 都是共享的。假如每个阶段之间的参数不共享,那么 RNN 就无法提取出序列中蕴含的共有特征,将退化为普通的神经网络。所以权值共享是 RNN 和普通神经网络之间的主要区别。这也是为什么我们要用 RNN 来学习二进制加法,因为 RNN 可以学习到两个二进制序列相加过程中的进位这一共性概念。
2. 使用自动求导框架构建 RNN 实现二进制加法
这一部分我是参考了 Anyone Can Learn To Code an LSTM-RNN in Python (Part 1: RNN) 这篇文章,将这个简单的神经网络用我的框架实现了一下。下图是使用框架提供的基本模块构建的 RNN 模型的虚拟图。
虚拟图中有一个大的 LoopNode 表示了需要对 LoopNode 中的子虚拟图循环遍历多次。子虚拟图是 RNN 每个循环阶段的结构,每个阶段和上一个循环阶段通过Branch:1这个虚拟节点连接起来,首次循环的时候Branch:1会向其子节点 Add:1 提供一个全0的矩阵来初始化循环,以后每次循环 Branch:1 则向 Add:1 提供上一次循环中 Mult:h 这个虚拟节点生成的计算节点。整个结构可以参考本文最上面的循环神经网络那张图,Parameter:u,Parameter:v,Parameter:w 分别对应了那张图中的 U,V,W 参数。
由于本框架在某个虚拟节点生成多个计算节点时,提供了其生成的计算节点参数共享的支持,所以使得 Parameter:u,Parameter:v,Parameter:w 这三个虚拟节点在多个循环中所生成的各自计算节点参数共享。通过本框架构建 RNN 不需要手动推导反向传播,提高了开发效率。
使用本框架主要的过程可以参考自动求导框架项目源代码的 unit_test/rnn_test.cpp 下的实现,主要分为生成数据集,生成虚拟节点,构造虚拟图,框架构建计算图,基于计算图进行迭代训练。训练方式采用随机生成10000个256以内的数字转化为二进制数进行训练,总共训练20000次,每次训练两个数字相加。每1000次打印一下当前数字加法的预测结果。下面是加法训练的结果:
可见在第3000个样本时候该神经网络已经可以正确理解加法的进位概念,得到正确的计算结果。