1.代码阅读
我选择的文章是"Structural-RNN: Deep Learning on Spatio-Temporal Graphs",是康奈尔和斯坦福的学者发表于2016年CVPR的一篇文章,作者提出了一种结合高阶时空图像和循环神经网络的方法,赋予了深度循环神经网络更加直观的高阶时空架构,并利用这种新结构解决一些实际问题,均取得了较好的效果。我综合课本和Github上开源的代码对该文章进行了仿真实现,在这里对实验过程及结果进行说明。
S-RNN结构是基于Theano实现的,Theano是一个Python库,可以在CPU或GPU上运行快速数值计算,它能巧妙的采用一系列代码优化从硬件中攫取尽可能多的性能,并且充分加速Numpy库和Scipy库的计算,在用Python进行深度学习是,Theano库由于其优越的性能被广泛使用,能创建深度学习模型,对库进行包装,在很大程度上简化程序。
本篇文章中的S-RNN基于Theano库搭建了NeuralModels库,他能很好地建立循环神经网络,并且能快速方便的对循环神经网络进行建模。NeuralModels的地址为:
https://github.com/asheshjain399/NeuralModels
在安装好NeuralModels库之后,我们可以方便的构建S-RNN结构,并且用它来实现文章中提到的动作检测和行为预测。
使用S-RNN结构进行动作检测和行为预测的代码地址如下:
https://github.com/asheshjain399/RNNexp
所以代码仿真的整体顺序为:
- 安装Theano环境
- 安装NeuralModels库
- 使用S-RNN实现文中提到的实验内容
通过学习NeuralModels库文件的代码,可知库文件的结构如下:
图1-1 NeuralModels库文件
接下来对各个文件的功能进行说明:
NeuralModels是一个Python编写的神经网络模型,包含了各种深度神经网络层的定义,优化方法以及几个模型。
在layers目录是一些层的定义,在深度学习框架中有许多层是具有特定功能并且通用的,NeuralModels库中的说明如下:
这一层是使用Gradient clipping的LSTM算法层,在这里关键理解两个概念,第一是什么是Gradient Clipping,其次什么是LSTM算法。
首先解释一下LSTM算法的概念:
LSTM是对循环神经网络(RNN)的一种改进,普通的循环神经网络虽然有记忆功能,能够把之前的信息连接到当前的任务上,但是实际上,要想达到好的效果,还有很多依赖因素。例如,我们有一个语言模型用来基于先前的词来预测下一个词。如果我们试着预测"the clouds are in the sky"最后的词,我们并不需要任何其他的上下文——因此下一个词很显然就应该是 sky。在这样的场景中,相关的信息和预测的词位置之间的间隔是非常小的,RNN 可以学会使用先前的信息。但是同样会有一些更加复杂的场景。假设我们试着去预测"I grew up in France... I speak fluent French"最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。不幸的是,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。而LSTM网络通过刻意的设计有效避免了长期依赖问题。对于LSTM模型的解释这里不再多做赘述,我在代码学习的过程中主要是通过这篇文章来了解的:http://www.jianshu.com/p/9dc9f41f0b29/
Gradient Clipping在循环神经网络中非常常见,当梯度进行传播时,如果他们连续乘以小于1的数字,最后可能消失,这也就是我们所说的Vanishing Gradient Problem.当然,如果连续乘以大于1的数字,梯度可能特别大,这被称为梯度爆炸,Gradient Clipping可以把梯度限制在两个数字之间,使梯度变化的范围可控。
用这一层网络可以创建一个具有Skip-input and output connection的LSTM堆栈,在不需要使用Skip-input and output connection的情况下,就会简单的创建一个多层LSTM数组。
什么是Skip connection呢,他是被用来连接高等级和低等级特征值的一种方法,例如一个动作序列当中的上下文语义特征和单纯图像的像素特征,前者是高级特征,后者是低级特征,使用Skip Connection可以把二者结合起来。
layers/simpleRNN.py
这是简单的循环神经网络层。
Softmax层,一般是深度神经网络结构的输出层。Softmax函数将多个标量映射为一个概率分布,其输出的每一个值范围在(0,1)。公式如以下所示:
softmax函数经常用在神经网络的最后一层,作为输出层,进行多分类。关于Softmax层我主要是通过该链接进行理解的:
http://www.jianshu.com/p/cb93d5e39bca
OneHot层生成一个one-hot的矢量表示,通常用于有限大小的词汇的架构输入层。方便后期的计算和处理。
我对它的具体理解主要参考该网页:
http://www.cnblogs.com/lzh-cnblogs/p/3764749.html
这一层也是用于处理数据的输入层,输入的数据的大小为T*N*D
T: the number of time-steps.
N: the number of sequences.
D: the Dimension of each feature vector.
连接两个层,是1-1的连接,
多个层的数据连接到一个层,即多个层的向量直接叠加到一起。
多维数据的输入层
单个层的多维数据变换到一维,即每个维度的向量直接叠加到一起。
在models目录是一些已经预实现的模型,具体说明如下:
这是在时空图上计算S-RNN的模型,也是我们的文章中主要使用的部分。在DRA模型中,边缘RNN和节点RNN都是以RNN的名字为key,一系列layers为value的字典。
节点和边缘的连接线也是一个字典,它的key是节点RNN的名字,value是另外一个字典,这个字典的key值是与那个节点RNN相连的边缘RNN,value值为一个两维的列表,表示用unConcatenateLayer中选择的要素。
节点的标签也是一个字典,它的key为节点的名称,而值是一个Theano的矩阵。
使用DRA的模型并且预测对应的输出。
这个模型可以连接来自多个RNN的高级特征,并能够将最终得到的特征向量输送到最后的combined_layer。
它的输入是一系列的RNN层:[[layers_1],[layers_2],...,[layers_N]],其中layers_N代表一个RNN。
Combined_layer是最后的一层,可以连接之前的rnn层传递来的向量。
这是一个带噪声的RNN实现。
这是一个简化的RNN实现。
通过因子分享可以实现RNN的结构化。
使用因子分享的RNN并且得到预测的结果。
文章中是把时空图作为S-RNN网络的向量输入,来进行深度学习的,那么怎么得到数据文件的时空关系呢,作者是手动标出并且进行处理的。
具体代码可以见/structural_rnn/CRFProblems/H3.6m文件夹的内容,在文件夹中dataParser文件夹和mhmublv文件夹中是对数据进行分组和矢量变换的文件,首先读取时空关系文件,以/structural_rnn/CRFProblems/H3.6m/crf文件为例,里面的内容为:
1 2 3 4 5 6 7 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">torso,right_arm,left_arm,right_leg,left_leg</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">torso,arm,arm,leg,leg</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">0,1,1,1,1</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">1,0,1,0,0</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">1,1,0,0,0</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">1,0,0,0,1</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">1,0,0,1,0</span> |
下面有一个5*5的矩阵,代表各个node之间的关系,每个节点分别是:脊椎,左手,右手,左腿,右腿,对于第一行,对脊椎来说,它与左手,右手,左腿,右腿都有交互,因此数据为0,1,1,1,1;但是对于第二行的左手来说,它只与脊椎和右手有交互,因此为1,0,1,0,0。以此类推可以认为的分割出其中的时空关系,并且对节点进行分组。在通过相关库函数进行具体转换,可以得到时空图数据集。
S-RNN框架得实现主要参考/NeuralModels-master/models/DRA.py文件中的内容。在该文件中定义了S-RNN框架的一个类。
如前文已经叙述过的,在DRA模型中,边缘RNN(edgeRNN)和节点RNN(nodeRNN)都是以RNN的名字为key,一系列layers为value的字典。
节点和边缘的连接线(nodeToEdgeConnections)也是一个字典,它的key是节点RNN的名字,value是另外一个字典(edgeListComplete),这个字典的key值是与那个节点RNN相连的边缘RNN,value值为一个两维的列表,表示用unConcatenateLayer中选择的要素。
节点的标签也是一个字典(nodeLabel),它的key为节点的名称,而值是一个Theano的矩阵。
函数中的初始化如下图所示:
首先,由于nodeRNN和edgeRNN都是value为一系列layers的字典,我们自下而上的构建网络,网络示意图如下:
图1-2 S-RNN示意图
采用自下而上的方式构建网络,首先遍历每一个nodeRNN节点,对于每一个nodeRNN节点,都可以通过nodeToedgeConnection得到与之相连的edgeRNN的列表,遍历该列表中的所有edgeRNN元素,每一个edgeRNN内部可能都有许多层,首先连接每个edgeRNN内部的层得到这些edgeRNN的输出,这一部分的代码如下:
第二步是使用Concatenate层将edgeRNN的输出和nodeRNN连接到一起的所以先将nodeRNN和edgeRNN内部的层连接起来,具体代码如下图所示:
最后连接每个nodeRNN内部的层,并且计算相应的nodelabel输出。这样利用前文已经提到过的layers可以实现S-RNN的框架。
文章中为了减少计算量,简化模型,还利用了节点间的因子分享方法,即在实际问题中一些结点或者边缘在语义上是相似的,可以分成一类,并且共享参数,这样一边面可以减少参数数量,另外一方面也可以增强框架适用于不同问题的灵活性。
具体的实现可以参考/NeuralModels-master/models/SharedRNN.py中的内容。
在SharedRNN中,分为shared_layers和其他普通层,首先将shared_layers部分的层内容相连,再将shared_layers分别和其他层相连,计算输出。具体代码截图如下:
除了以上内容外,在models的代码中还有一些具体函数,有特定的功能,并且这些函数的功能比较典型。以/NeuralModels-master/models/DRA.py中的相关函数为例进行说明:
fitmodel的参数是各种参数,这个函数的主要作用就是训练模型,并且利用测试集得出错误率或者预测结果。在模型已经存在的条件下,也可以读取相关模型,直接进行后期的预测。
saveForecastError的作用是计算测试集的正确率。
saveForecastMotion的作用是存储预测的动作信息。
saveCellState的作用是存储S-RNN过程中间态的计算信息,可以利用他们来进行一些动作的识别和区分。
predict_output的作用是预估节点的输出。
predict_sequence的作用是预估序列的输出。
predict_nextstep的作用预估下一步内容。
predict_cell的作用预估中间的cells。
Character-rnn在/NeuralModels-master/character-rnn/目录中,其中char-rnn.py是主程序,generateTrainDataOntext.py是读入数据的文件,数据集是一个4M大小的文本文件shakespeare_input.txt。这部分的作用是利用NeuralModels库构造多层RNN网络,学习莎士比亚作品并且进行预测输出。
在主函数中,首先定义一些参数,如训练样本数目,测试样本数目,每个样本的长度,迭代次数,衰变速率等等。然后使用creatTrain函数首先将文本转化为向量输入。接着定义网络层,在本例中以OneHot为输入层,三个LSTM层为中间层,softmax层为输出层定义RNN网络,并且将得到的checkpoints文件存储到当前目录的checkpoints的文件夹当中,这一部分的代码如下图所示。
程序很简单,在这里我想强调一下generateTrainDataonText.py的具体实现过程,这能帮助我们理解如何将文本文件转化成我们所需要的矢量输入。
首先读入文本文件,利用Counter函数得到文本出现过的所有字符以及他们对应的次数的字典。
然后创建字典,将文本中出现的所有字符与某个数字意义对应。这里创建两个字典,一个的key是字符,value是数字,用于将文本正变换为向量。另一个key是数字,value是字符,用于将数字向量反变换为文本。具体实现是在sample_text函数中实现的。这样说明可能会有点难以理解,我以比较直观的方式简单说明一下。
例如一开始创建了一个字典,将b字符与数字21对应,o字符与数字5对应,k字符与数字14对应,空格字符与数字18对应。那么book 这个单词可以表示为21 5 5 14 18这个向量,通过这种方式,可以把整篇文章改成数字表示,并且截取固定长度的数字为一个单位,做成向量,用他们作为SRNN框架的输入。便能很方便的进行后续的计算和操作。最后我们预测出的结果也会是数字,利用之前得到的字典将数字反变换成字符即为我们最后的结果。
实际上很多文本文件的矢量化都可以用这种方式来进行,这也是本文的代码中使用的主要方法。
这是本文中主要提的一个通过S-RNN框架结合时空图预测人体运动规律的例子,它使用的是已经归一化处理过的h3.6m数据集,数据集在附件中,在本文提供的数据集中,图片数据已经被数字化。
人体移动预测模型的代码可以在该网址下载:
https://github.com/asheshjain399/RNNexp/tree/srnn/structural_rnn
本实验的地址为:RNNexp-srnn/structural_rnn,其中的文件列表如下:
H3.6m文件夹是将H3.6m数据库根据时空关系转化为数据输入的文件,具体实现在1.3.1节已经说过了,这里不再赘述。
其中hyperParameterTuning.py是主程序,其中可以设置srnn模型,lstm3lr模型和erd模型的参数,基于这些参数可以训练出对应的模型并基于模型进行进一步的预测。
loadDRA.py用以读入h3.6m数据集,H3.6m中的文件主要对数据集进行处理。generateMotionForecast.py文件和forecastTrajectories.py可以生成预测的文件。
basedir文件中写入h3.6数据集存放的地址,生成的checkpoints文件也会放在对应的地址中。
人类行为预测模型的代码目录在/RNNexp-srnn/actibity-anticipation目录中,这个例子是通过对节点RNN和边缘RNN进行学习得出每个节点对应的标签。
文件目录如下:
其中activity-dra.py文件是使用s-rnn模型估计活动,而activity-rnn-full-model.py是计算分享因子的rnn模型,activity-rnn.py是直接使用rnn模型,activity_prediction_sharedrnn.py是使用分享因子的rnn进行预测,而activity_prediction_rnn.py是直接使用rnn进行预测,readData文件读取数据。
其中使用的库文件和技术在前文均有说明,在此不在赘述。
此外给出的实例文件中还给了用S-RNN框架进行行车预测的代码,但由于文章中对该案例只是提到并没有太大说明,且该部分的原理和前几个例子类似,因此并不对这一部分进行具体分析和仿真。其中使用的库文件和技术在前文均有说明。
2.实验过程与相关问题
2.1 实验环境搭建过程
2.1.1 Theano环境搭建过程
要使用S-RNN框架,必须安装NeuralModels库,而要安装NeuralModels库,则需要使用到Theano库,因此必须先在系统上安装Theano。
实际上,在作者给出的以下网址中:
https://github.com/asheshjain399/NeuralModels
作者提出使用 python setup.py develop指令即可自动安装NeuralModels框架,但是在实际的安装过程中,使用github的方法直接安装NeuralModels,Numpy库Scipy库和Theano库都会出现一些问题,因此需要自行安装numpy库,scipy库和matplotlib库。
一开始我是在自己笔记本的虚拟机上使用apt-get指令安装Numpy和Scipy,然后使用pip安装Theano的,但是在安装好后,发现使用该框架的计算速度非常慢,character-rnn例程在我的电脑上跑了三天才跑完,后来才发现直接安装的python库是没有加速的,所以要自己按照特定的步骤安装numpy和scipy,并且经过测试才行。
因为之前没有安装过类似的开发环境,这次的环境搭建过程花费了很多时间,收货也很多,在这里对该过程详细叙述一下,其中也有过程中遇到的问题与解决方法。
之前提到过,直接安装Scipy库和Numpy库进行数学运算时,由于没有加速,所以运算速度很慢,因此我们需要安装以下其他的库进行加速,在这里对相关库先进行介绍:
BLAS(Basic Linear Algebra Subprograms):
是基础线性代数子程序库,里面拥有大量已经编写好的关于线性代数运算的程序;
LAPACK (Linear Algebra PACKage):
包含了求解科学与工程计算中最常见的数值线性代数问题,如求解线性方程组、线性最小二乘问题、特征值问题和奇异值问题等;
ATLAS:
是python下的一个线性代数库,是基于另外两个线性代数库BLAS和lapack的;
NumPy:
提供了一个在python中做科学计算的基础库,它重在数值计算,甚至可以说是用于多维数组处理的库;
SciPy:
是基于numpy,提供了一个在python中做科学计算的工具集,也就是说它是更上一个层次的库;
Theano:
则是基于NumPy以及SciPy的一个更高级的用于科学计算的库。
要安装Theano,就需要先安装好numpy和scipy;要安装numpy和scipy,就需要ATLAS;要安装ATLAS,就需要安装BLAS和LAPACK;所以在这里我们的安装顺序应该是BLAS-LAPACK-ATLAS-Numpy-Scipy-Theano。
因为一开始我的numpy和scipy库是通过apt-get指令安装的,所以没有与Atlas库建立依赖,因此当我试用以下两句指令进行Numpy库和Scipy库的测试时,显示有failures,测试并不通过。
1 2 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">python -c "import numpy;numpy.test()"</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">python -c "import scipy;scipy.test()"</span> |
所以先要卸载之前安装的numpy和scipy:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">卸载</span><span style="font-family:Consolas">numpy</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get remove python-numpy</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">卸载</span><span style="font-family:Consolas">scipy</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get remove python-scipy</span> <span style="font-family:微软雅黑; font-size:12pt"> 然后安装Atlas的加速包和Openblas的加速包:</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">安装</span><span style="font-family:Consolas">gfortran,</span><span style="font-family:微软雅黑">后面编译过程中会用到</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get install gfortran</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">安装</span><span style="font-family:Consolas">blas,Ubuntu</span><span style="font-family:微软雅黑">下对应的是</span><span style="font-family:Consolas">libopenblas</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get install libopenblas-dev</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">安装</span><span style="font-family:Consolas">lapack</span><span style="font-family:微软雅黑">,</span><span style="font-family:Consolas">Ubuntu</span><span style="font-family:微软雅黑">下对应的是</span><span style="font-family:Consolas">liblapack-dev</span><span style="font-family:微软雅黑">,和</span><span style="font-family:Consolas">OS</span><span style="font-family:微软雅黑">相关。</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get install liblapack-dev</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas"># </span><span style="font-family:微软雅黑">安装</span><span style="font-family:Consolas">atlas</span><span style="font-family:微软雅黑">,</span><span style="font-family:Consolas">Ubuntu</span><span style="font-family:微软雅黑">下对应的是</span><span style="font-family:Consolas">libatlas-base-dev</span><span style="font-family:微软雅黑">,和</span><span style="font-family:Consolas">OS</span><span style="font-family:微软雅黑">相关。</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get install libatlas-base-dev</span> |
之后使用pip指令安装Numpy和Scipy,测试通过
1 2 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">sudo pip install numpy</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo pip install scipy</span> |
在安装完成之后,ubuntu进入到/NeuralModels-master/目录下,执行python setup.py develop指令安装NeuralModels库,此时出现问题:
1 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">ImportError: No module named matplotlib.pyplot</span> |
这是因为缺少matplotlib库造成的,解决方法是安装metplotlib
先装预装库
1 |
<code><span style="color:#333333; font-family:Consolas; font-size:10pt">sudo apt-get install libpng-dev </span> |
安装freetype:
1 2 3 4 5 6 7 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">cd ~/Downloads </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">wget http://download.savannah.gnu.org/releases/freetype/freetype-2.4.10.tar.gz </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">tar zxvf freetype-2.4.10.tar.gz </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">cd freetype-2.4.10/ </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sh ./congfigure </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">make </span> <span style="color:#333333; font-family:Consolas; font-size:10pt">sudo make install </span> |
安装matplotlib
1 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">sudo pip install matplotlib </span> |
这样matplotlib的问题解决。
然后又出现问题:
1 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">No module named _tkinter, please install the python-tk package </span> |
解决方案:
sudo apt-get install python-tk
问题解决,然后再次出现问题:
1 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">ImportError: Need nose >= 1.0.0 for tests </span> |
解决方案:
pip install -U --force --user nose
至此Theano框架安装成功,并且使用Atlas加速,运行character-r程序的速度提升到了三小时。
但是在这样的环境下,计算速度依旧不快,并且由于我是在电脑的虚拟机上运行的,一方面不能使用GPU加速,另外一方面经常会出现内存冲突的问题导致程序中断,因此后期使用了另一台带有双显卡的计算机,并且尝试对Theano进行进一步加速。
通过之前的安装我发现,使用不同的安装方式,最后运行的速度会有很大的差别,并且不能用虚拟机安装类似的深度学习框架进行深度学习,因为虚拟机不能使用GPU加速运算,也不能充分利用硬件资源,运算速度受到较大限制。
此外,加速Theano库的方式有两种,第一种方法是我们之前用的,先安装Atlas,然后再Atlas的基础上安装Numpy和Scipy,这样的运行速度会快10倍左右,因为Atlas会对python的库进行加速。当然还有一种更快的方法是使用OpenBlas对Numpy和Scipy进行加速,这样的速度是目前最快的,并且Theano默认是使用OpenBlas加速,所以使用起来也更方便。因此在这里我重新使用这种方法安装环境并进行测试。在这之后,为了充分发挥服务器的性能,我也进行了一定的配置,使用GPU加速。接下来将配置过程以及相关问题进行说明:
1.安装OpenBlas
这一部分主要参考以下链接:
http://deeplearning.net/software/theano_versions/dev/install_ubuntu.html
http://www.linuxdiyf.com/linux/15610.html
https://github.com/xianyi/OpenBLAS
在github上下载好Openblas的代码以后:
1 2 3 4 5 6 7 8 9 10 11 12 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">git clone git://github.com/xianyi/OpenBLAS</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">cd OpenBLAS</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas">make FC=gfortran</span><span style="font-family:微软雅黑">(如果没有安装</span><span style="font-family:Consolas">gfortran,</span><span style="font-family:微软雅黑">执行</span><span style="font-family:Consolas">sudo apt-get install gfortran</span><span style="font-family:微软雅黑">)</span></span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas">make install (</span><span style="font-family:微软雅黑">将</span><span style="font-family:Consolas">OpenBLAS</span><span style="font-family:微软雅黑">安装到</span><span style="font-family:Consolas">/opt</span><span style="font-family:微软雅黑">下</span><span style="font-family:Consolas">)</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">ln -s /opt/OpenBLAS/lib/libopenblas.so /usr/lib/libblas.so.3</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">ln -s /opt/OpenBLAS/lib/liblapack.so.3 /usr/lib/liblapack.so.3</span> <span style="font-family:微软雅黑; font-size:12pt"> 最后两条命令是让全局可以找到OpenBlas,避免出现找不到链接库的问题,我在编译的过程中碰到了这个问题:</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">/usr/bin/ld: cannot find –lopenblas</span> <span style="font-family:微软雅黑; font-size:12pt"> 但是我已经OpenBlas库,它却提示找不到链接库,这是因为链接库的链接不正确,因此对它进行了修改:</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">cd /usr/lib</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">ln -s libXtst.so.6 libopenblas.so</span> <span style="font-family:微软雅黑; font-size:12pt"> 具体参考的是以下链接:</span> |
http://www.jb51.net/LINUXjishu/211594.html
之后按照前一部分的说明安装Numpy和Scipy,网络上有一种方法是让我们下载源文件直接编译,我尝试过之后发现有很多问题,并且测试也不能通过,因此最后我使用的还是pip安装。测试成功。
2.安装Cuda
为了使用GPU加速,需要安装cuda和Nvidia SDK以及相关硬件驱动,然后设置.theanorc文件将其设置为硬件加速。
在工程目录中新建.theanorc文件,例如我的电脑名字是达达,则建立在/home/dada/目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">cd /home/dada </span></code><code><span style="color:#333333; font-family:Consolas; font-size:10pt">vim .theanorc </span></code><span style="font-family:微软雅黑; font-size:12pt"> 在theanorc目录中添加以下内容:</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">[global]</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">device=gpu</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">floatX=float32</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas">root=/usr/local/cuda</span><span style="font-family:微软雅黑">(这里填自己</span><span style="font-family:Consolas">cuda</span><span style="font-family:微软雅黑">的地址,一般在</span><span style="font-family:Consolas">/user/local</span><span style="font-family:微软雅黑">目录下)</span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">[nvcc]</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">fastmath = True</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">[blas]</span> <span style="color:#333333; font-size:10pt"><span style="font-family:Consolas">ldflags = -lopenblas</span><span style="font-family:微软雅黑">(使用</span><span style="font-family:Consolas">openblas</span><span style="font-family:微软雅黑">)</span><span style="font-family:Consolas"> </span></span> <span style="color:#333333; font-family:Consolas; font-size:10pt">[cuda]</span> <span style="color:#333333; font-family:Consolas; font-size:10pt">root = /usr/local/cuda</span> <span style="font-family:微软雅黑; font-size:12pt"> 之后按照链接http://www.csdn.net/article/2015-08-07/2825415中的文件进行测试,显示gpu则配置成功。</span> |
在我的安装过程中,出现了下列问题:
1 |
<span style="color:#333333; font-family:Consolas; font-size:10pt">nvcc compiler not found on $PATH. Check your nvcc installation and try again</span> |
http://www.th7.cn/system/lin/201604/162762.shtml
至此,环境的安装工作完成,跑char-rnn.py的例程,此时使用GPU加速+openblas是10分钟,如果是atlas且没有GPU加速我跑了4小时,如果atlas也没有我跑了3天。由此可见正确的环境对深度学习速度的重大影响。
在以上环境安装好,并且其中遇到的问题解决后,代码都能正常运行,接下来简要提一下每个例子的编译过程和遇到的问题,以及最后的解决方案。
Character-rnn是验证NeuralModels库是否安装好的示例文件,运行指令为:
前面已经提到,不同的主机运行环境,编译和运算的速度也不一样,使用直接安装的Theano库需要三天时间才能完成训练过程,使用Atlas和Theano的配置需要3小时,而使用openblas和gpu加速只需要10分钟。
代码的编译需要安装numpy库,scipy库,matplotlib库,python-tk库,nose库等,不然会报错。
此外,如果电脑的虚拟内存不足,可能会在中途直接结束退出,我碰到过几次这样的情况,所以电脑的性能还是很重要的。
通过学习Character-rnn的代码,我们也能很方便的构建自己所需要的深度学习网络架构。比如如果我想要创建一个有三层LSTM层的RNN网络,并且输入结构是已经计算好的特征向量,而输 出是一个softmax层,则可以按照这样的顺序建立模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span style="font-size:12pt"><span style="font-family:微软雅黑">1.导入对应的</span><span style="font-family:Times New Roman">Python</span><span style="font-family:微软雅黑">库</span></span> import theano from theano import tensor as T from neuralmodels.layers import * from neuralmodels.models import * from neuralmodels.updates import Adagrad from neuralmodels.costs import softmax_loss <span style="color:#333333; font-family:Consolas; font-size:10pt"> </span></code><span style="font-size:12pt"><span style="font-family:微软雅黑">2.定义网络层的结构</span></span> layers = [TemporalInputFeatures(inputDim),LSTM(size=512),LSTM(size=512),LSTM(size=512),softmax(size=numClasses)] <span style="font-size:12pt"><span style="font-family:微软雅黑">3.创建模型</span></span> trY = T.lmatrix() initial_step_size = 1e-3 model = RNN(layers,softmax_loss,trY,initial_step_size,Adagrad()) <span style="font-size:12pt"><span style="font-family:Times New Roman">4.</span><span style="font-family:微软雅黑">使用</span><span style="font-family:Times New Roman">fitModel</span><span style="font-family:微软雅黑">函数训练该模型</span></span> |
该实例使用H3.6m数据集,对人体行为进行预测。
编译过程如下,首先下载H3.6m数据集,并且在basedir中输入H3.6m数据集存储的地址,原本的H3.6m数据集是图片,但是作者已经预处理成了文本形式。
在/structural_rnn/CRFProblems文件夹中,是将H3.6m库根据时空关系分离所使用的库,在函数运行的过程中,会首先调用该文件的函数将数据集分离成时空图的相关变量。
可以使用S-RNN框架,ERD框架和LSTM-3LR框架对函数进行训练,使用的指令如下:
1 2 |
python hyperParameterTuning.py model |
其中的model可以是srnn或erd或者lstm3lr中的一种,分别代表使用对应的框架进行训练。在hyperParameterTuning.py函数中,可以对模型的参数进行定义,具体参数有收敛于这,学习速率,迭代次数,噪声比,序列场地,梯度,节点和文本大小,训练对象等等,通过修改这些值可以改变框架的性能,让它适应不同的问题。
hyperParameterTuning.py函数内部会调用trainDRA.py文件,这个文件可以建立我们的模型并对它进行训练,将训练结果输入到对应的结果文件夹中。
一旦训练结束,trainDRA.py文件也会自动调用generateMotionData.py文件,改文件会生成预测的结果并输入到generate.py文件夹中。
当然,在程序运行结束之后,我们也可以使用如下指令利用已经训练好的模型生成预测结果:
1 2 |
python generateMotionForecast.py model path |
其中的model是srnn或erd或者lstm3lr中的一种,分别代表使用对应的框架进行预测,而path指的是之前生成的存放checkpoint的地址,该程序是存放在H3.6m数据集对应的文件夹中。
在使用虚拟机运行该模型的训练时,还出现了一个问题:
1 2 |
os.fork():Cannot allocate memory |
这是因为虚拟机的内存不够,换了服务器之后问题解决。
在文章中,作者还提到,可以使用该框架生成混合人体移动模型,在实际运行中是在已经生成checkpoint数据点之后,调用generatemixMotion.py文件,指令如下:
1 2 |
python generatemixMotion.py |
可以在checkpoint的目录下生成混合移动模型的结果。
在文章中,作者还提到,可以使用S-RNN框架用于人体行为的检测和预测,作者使用的是CAD-120数据集,CAD-120数据集是康奈尔大学使用Kinect传感器记录的人类活动序列,一共有10个高级活动:做谷物,服药,堆放物体,拆卸物体,微波炉加热食物,拾取物体,清洁物体,采取食物,安排物体;还有10个子活动标签:到达,移动,倾倒,吃,喝,打开,放置,关闭,擦洗;12个物品提供标签:可达,可移动,可倾倒,可倾倒,可收藏,可饮用,可打开,可放置,可关闭,可洗涤,洗涤器。所以使用这个数据集本身可以较好的得到视频序列中的时空关系。
在作者的github链接中没有给出该实验的数据集,但是直接使用CAD120数据的RAW文件,并无法直接转化为时空图和相关的矢量输入,因此这个实验难以编译复现,故本人只是对代码进行了分析,并没有编译这个实验过程。
但是Activity-anticipation的原理和之前H3.5m数据库的原理基本是类似的,所以对于文章的理解并没有大影响。
运行Character-rnn的实验数据在文件夹checkpoints中,在运行完成之后,里面有30个checkpoint文件,相当于经过30次迭代之后每次迭代的训练结果文件,还有一个文件是logfile,这是训练过程中输出的loss_rate的log,代表文件的收敛程度。
在进行数据分析之前,先接受几个比较重要的概念,在character-rnn.py文件中,一开始定义了一些变量:
epoch:1个epoch等于使用训练集中的全部样本训练一次,这里相当于所有样本训练30次,因此会得到30个checkpoint文件,并且由于每一次训练都是基于前一次的训练基础,因此训练过程中loss会不断减小。
batch_size: 一次Forword运算以及BP运算中所需要的训练样本数目,其实深度学习每一次参数的更新所需要损失函数并不是由一个{data:label}获得的,而是由一组数据加权得到的,这一组数据的数量就是[batch size]。当然batch size 越大,所需的内存就越大,要量力而行.
Learning_rate_decay: 权值衰减的作用是防止过拟合,在损失函数中,weight decay是放在像前面的一个系数,正泽祥一般指示魔性的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也就越大。
观察数据可知loss一直在减少,到epoch为30次是在510左右波动,基本不变,仔细观察也能发现算到后面loss趋于稳定,此时预测输出的文本结果如下:
1 2 |
["\n\nPirther:\nNo' thee, and my leader, if my leave,\nStand the wear this word the grick prose of his been\nOf consertious\nThe preation haw dich bings her monest.\n\nPORTIA:\nThe great of a gurt doamfess and nature\nThis fure that did from what Gost.\n\nANGELO:\nO, and the the hall be fair of worthy deserp:\nThe deebuchs on themell, the prialieds,\nTo he to keep the thangent the present couse.\nPad, mand think is nather dich kain love to do,\nAnd the stail men will many moraned.\n\nPERICLES:\nIt madis, thou shall he therefore bofs so delame\nWell undore and heart both a jouce:\nAnd pity is now word.\n\nCARILA:\nWhy, whe other wear therefore laded anouse.\n\nRISELAND:\nTill me the dead and it with commist of my my lord.\n\nBRUTUS:\nAs, there, sirlemas, that I will me his day,\nWhon I have colerne and the butters,\nMant end that come and the weatand erpant it.\n\nBOATRICE:\nYou bouse, and well as for thee warren as brother:\nIf is words alatience in the frood:\nAnd me and parsion for the dainoos.\nSo made a dried not from tha"] |
以上是根据前面的内容预测出来的话,虽然还是比较乱,但是可以看出一定的预测效果。
使用S-RNN框架对H3.6m数据集进行人体运动估计的时候,首先使用s-rnn框架,生成文件在目录checkpoints_dra_T_150_bs_100_tg_10_ls_10_fc_10_demo中,其中checkpoint开头的文件是生成的训练结果,forecast_error_iteration开头的文件是预测的匹配率,forecast_iteration开头的文件是生成的短时预测的结果,而forecast_iterationlong开头的文件是生成的长时间活动预测的结果,ground_truth_forecast开头的文件时短时预测的参照文件,而ground_truth_longforecast是长时间预测的参考文件。
我对srnn,erd和lstm3LR进行了比较,其中srnn的训练速度明显快于erd和lstm3lr算法,同样参数下,srnn的运行结果erd和lstm3lr的结果,和文章中给出的结果一致。
整体来说这次实验的仿真过程有很多收获,首先对S-RNN框架,深度神经网络结构有了更多的了解,此外亲手完成代码的复现,也让我熟悉了这套框架,并且了解了一些问题和注意要点。
对于这篇文章我也有了更深的了解,首先期中存在的几个问题都在仿真的过程中得到了答案:
我期中时列出的问题如下:
- 首先,本文并没有说明是如何把一个序列的图像变成时空图的,即我们并不知道如何分割出其中的人和物,并且知道人和物的边缘关系,时空关系等。我觉得有两种可能,第一是已经认为标定了节点和边缘,后期不用进行分割,只要直接计算即可,但是这样的实用性就不强,因为它没有考虑到分割的问题,以及有误识别或误分割对S-RNN的影响。另外一种方式则是使用一些开源的人体检测和物体检测算法,提取出其中的人和物,比如可以使用轮廓提取+HOG特征检测+SVM分类的方法,但是对于不同的应用环境,需要检测的对象并不相同,这样检测算法也需要改变,这样这个系统不能称之为具有普适性,因为他的数据集预处理需要采用不同的处理方式。当然还有可能有其他的处理方式我并没有想到,后期可以看一些关于时空图处理的文章加以分析。
- RNNs网络有很多参数需要调节,如网络层数,每一层的神经元个数,迭代步长,收敛阈值,收敛上限等等,不同的RNNs网络最后得到的结果可能完全不同,所以在进行代码仿真时这部分还需要进行长时间的调参。
- 在时空图因子参数化的过程中,作者每个结点用一个因子函数表示,而每个边缘也用一个因子函数表示表示,展开后如图2-7-c建立S-RNN架构的数学模型,但是文章中并没有说函数的具体表示方法,当然这里也可能是随机确定权值,需要用梯度法或其他方法迭代计算,但因为文章还没说,目前并不是很清晰。
现在看来,第一个问题,把序列的图像先转化成对应的文本文件,可以用H3.6m试验中类似的方法,手动的标出各个节点的时空关系,然后利用character-rnn中吧harrypoter文本转化为向量类似的方法和CRF的现成库文件,实现时空图关系的标定和相关向量的输入获取。
第二个问题在代码中已经详细的列出了相关的参数,并且我也查了一些资料,具体了解了他们的应用与相关的功能,收获颇多。
第三个问题也是有已经确定的参数和网络层的种类决定的,并且nodeRNN和edgeRNN以及相关连接线的定义方式在之前也已经有过说明。
S-RNN框架充分利用了共享因子和结构化的设计,通用型较强,这在这几个实验当中都有体现,计算复杂度与RNN网络内部的层数有关。不过因为深度学习方面接触的其他算法较少,所以性能方面我并没有特别明显的感受,今后多接触一些其他的算法可以对文章有更多的体会。
此外,值得一提的是,我现在也能利用Theano框架,自己建立一些深度循环神经网络用以机器学习或预测问题,把知识转化为实用技能是一个很大的收获。
[1] Jain A, Zamir A R, Savarese S, et al. Structural-RNN: Deep Learning on Spatio-Temporal Graphs[J]. arXiv preprint arXiv:1511.05298, 2015.
[2] Sridhar M, Cohn A G, Hogg D C. Learning functional object categories from a relational spatio-temporal representation[C]//ECAI 2008: 18th European Conference on Artificial Intelligence (Frontiers in Artificial Intelligence and Applications). IOS Press, 2008: 606-610.
[3] http://asheshjain.org/srnn.
[4] https://www.zybuluo.com/hanbingtao/note/476663
[5] https://www.zybuluo.com/hanbingtao/note/541458
[6] https://github.com/asheshjain399/NeuralModels
[7] https://github.com/asheshjain399/RNNexp/tree/srnn/structural_rnn
[8] http://blog.csdn.net/xuezhisdc/article/details/47065475
[9] http://www.deeplearning.net/software/theano/
[10] http://www.openblas.net/
[11] https://github.com/xianyi/OpenBLAS/wiki/Installation-Guide
[12] http://www.csdn.net/article/2015-08-07/2825415
[13] http://www.th7.cn/system/lin/201604/162762.shtml
[14] http://stackoverflow.com/questions/41678837/no-module-named-nose-parameterized-during-theano-installation
[15] http://www.jb51.net/LINUXjishu/211594.html
[16] http://www.linuxdiyf.com/linux/15610.html