深度网络的设计与可视化工具

简介与目标

能够使用常见的framework。

  1. 快速的搭建环境
    • 从源码编译,可以采用并行编译系统,以及Clang来加速
    • 快速的部署,能够使用docker来进行部署
  2. 能够扩展开发工具本身
    • 快速的进行trace,以及anlyasis进行各种可视化分析
    • 快速的调试
    • 并且能够优化
  3. model本身的导入与导出
  4. model模型结构层极模型可视化
  5. model的简化
  6. 实现持续的CI
    • 持续的训练
    • 持续的交付
    • 持续的反馈
    • 持续的实验,也就是GIT的流程深度化,在同一个基线版本上,同时开始尽可能多的试验。然后就是不断的集成。然后rebase.

工具

对于神经网络的应用,各种网络之间的适配那就是矩阵乘,以及如何把种数据转化为矩阵。 #. 神经网络设计工具:(CAFFE,theao)。 #. 可视化:信息流的可视化(编码),训练时的可视化(过拟合,迭代下降)。 #. 网络拓扑本身的可视化。

Comparison with Other Frameworks

https://raw.githubusercontent.com/chainer/chainer/396bc3ee8a781463734c7dfac4e892ee6f578dc5/docs/source/comparison.rst

A table for quick comparison

This table compares Chainer with other actively developed deep learning frameworks. Content is current as of July 2017.

    Chainer PyTorch TensorFlow Theano-based Caffe1/Caffe2 Torch7 MXNet DyNet PaddlePaddle DL4J CNTK neon Knet.jl Darknet Thinc
Basics Language Python Python Python Python Python/C++/ MATLAB LuaJIT Python/others Python/C++ Python/C++ Java BrainScript/ Python/C++ Python Julia C Python
  Approach define-by-run define-by-run symbolic autograd symbolic autograd static static/ manual grads symbolic autograd/ manual grads/ define-by-run [1] define-by-run symbolic autograd static/ manual grads/ symbolic autograd [2] static/ symbolic autograd static/ symbolic autograd [3] define-by-run static callback-based define-by-run
  CPU backend package NumPy TH Eigen NumPy   TH mshadow Eigen   ND4J   NumPy Julia   NumPy
  GPU backend package CuPy THC Eigen libgpuarray   THC mshadow Eigen   ND4J   neon KnetArrays   CuPy
  Primary sponsor Preferred Networks Facebook Google MILA Facebook Facebook Amazon/Apache CMU Baidu Skymind Microsoft Intel Nervana Koç University Joe Redmon Explosion AI
NNs CNNs full full full full full full full partial full full full full partial full none
  RNNs full full full full partial full full full full full full partial partial partial partial
  Reverse-mode autograd Y Y Y Y   torch-autograd Y Y Y   Y ngraph Y   with closures
  Forward-mode autograd     tensorflow-forward-ad Y                      
  Higher-order grads   Y Y Y                 Y    
  Variable-length loops native native while_loop scan RNNs only native 2017 native RNNs only none dynamic axis none native none native
  Different architectures per batch native native fold     torch-autograd MinPy native         native   native
Performance cuDNN support full full partial partial full full full partial full partial full N/A [4]   partial  
  CPU/GPU generic backend Y Y       Y Y Y Y Y Y Y Y   Y
  Multi-GPU data parallelism Y Y Y Y Y Y Y   Y Y Y Y Y Y  
  Multi-GPU model parallelism Y Y Y Y Y Y Y   Y   Y Y      
  Multiprocessing [5] full partial           full              
  Distributed training ChainerMN THD Y   2017 torch-distlearn Y   Y Spark Y Y      
Misc Runtime debugging debug mode, typechecking, pdb pdb tfdbg       Monitor pdb   Java debuggers cntk.debugging   Gallium.jl gdb pdb
  Trainer abstraction native tnt   Blocks, Lasagne, Keras native torchnet     native native native native     native
  Reporter abstraction native tnt native     torchnet native     native native        
  Web interface     TensorBoard             DL4J-UI   Nervana Cloud      
  Graph compilation engine   2017 XLA   2017   NNVM         ngraph      
[1]Define-by-run is in development as of June 2017 and tracked in dmlc/mxnet#5705. It is also possible using the much slower MinPy extension.
[2]Symbolic autograd is in development as of June 2017 and tracked in deeplearning4j/nd4j#1750.
[3]Symbolic autograd is available only with ngraph backend (experimental).
[4]Nervana provides kernels that are meant to compete with cuDNN.
[5]Multiprocessing provides a significant performance improvement only for frameworks that use Python at runtime.

NVIDIA GIGITS

https://github.com/NVIDIA/DIGITS

  1. install CUDA
  2. install nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
  3. pip install
# example location - can be customized
DIGITS_ROOT=~/digits
git clone https://github.com/NVIDIA/DIGITS.git $DIGITS_ROOT
sudo pip install -r $DIGITS_ROOT/requirements.txt
sudo pip install -e $DIGITS_ROOT
./digits-devserver

https://github.com/NVIDIA/DIGITS/blob/master/docs/BuildDigits.md

caffe

Linux环境的准备

主要是根据 caffe install manual 来进行的。主要库的依赖可以用这个 https://github.com/gwli/StudyNote/blob/master/caffe/install/prepare.py 来完成安装。

nvidia driver 的安装

  1. 官网 下载最新driver,

  2. 进入字符介面 tty1

    ctl+alt+F1

  3. 关掉 X windows.

    sudo service lightdm stop

  4. 安装driver.

    chmod +x installer.run;./installer.run

  5. 恢复 X windows.

    sudo service lightdm start

Note

正常的情况下installer会自动disable的自带的driver,如果失败的重起一下,重新执行installer就行了。

安装cuda-toolkit

这里从两种方式来安装,手动安装,或者使用 jetpack pro 只安装 host端的cuda-toolkit.

  1. 添加源

    $ dpkg -i cuda-repo-ubuntu1404_6.5_amd64.deb
    
  2. 安装 cuda toolkit

    $ sudo apt-get install -y cuda-toolkit-6-5
    
  3. 配置环境变量

      $ export PATH+=:/usr/local/cuda-6.5/bin/:
      $ LD_LIBRARY_PATH+= /usr/local/cuda-6.5/bin/lib:
      $ export LD_LIBRARY_PATH
    
    .. note::
    
       也可以直接写.bashrc中就行,重启shell就行了。
    

相关库的安装

直接使用 https://github.com/gwli/StudyNote/blob/master/caffe/install/prepare.py 来完成就行了。

下面几个不常见库的说明

libs
Lib names Content Remark
google-glog google提供的一个C++的logging库 https://code.google.com/p/googl有e-glog/
protobuf-devel 性能更好的jason用于进程通信 相当于TCP/IP的包解析技术用在了进程通信IPC.
gflags 类似于getopt命令行处理接口 http://dreamrunner.org/blog/2014/03/09/gflags-jian-ming-shi-yong/
google snappy 一个高速的压缩库,http://www.infoq.com/cn/news/2011/04/Snappy  
google leveldb LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.,https://github.com/google/leveldb  

安装cudnn

  1. 从 ·https://developer.nvidia.com/cuDNN 下载 linux 官

  2. 解压安装

    $ tar -xzvf cudnn.tgz
    $ mv cudnn /usr/local/cudnn
    
  3. 修改LD_LIBRARY_PATH

      LD_LIBRARY_PATH+=:/usr/local/cudnn:
      C_INCLUDE_PATH+=:/usr/local/cudnn:
      CPLUS_INCLUDE_PATH+=:/usr/local/cudnn:
    
      PATH+=:/usr/local/cuda-6.5/bin:
      LD_LIBRARY_PATH+=:/usr/local/cuda-6.5/lib64:
      LD_LIBRARY_PATH+=:/usr/local/cuda/cudnn:
      export LD_LIBRARY_PATH
      C_INCLUDE_PATH+=:/usr/local/cuda/cudnn:
      CPLUS_INCLUDE_PATH+=:/usr/local/cuda/cudnn:
    
    由于采用 cudnn 的库与caffe兼容性问题,现在 caffe 与V1 是工作的。
    
    一个快速灵活的办法,那就是link.
    
    .. code-block:: bash
    
       ln -s  /usr/local/cudnn-6.5-linux-x64-v2-rc2/ /usr/local/cuda/cudnn
    

build

caffe 采用了大量的template,所以代码模式基本

digraph flow {

    template->code->"PIC so"-> "link to app";
}
  1. build the app

    make all |tee make.log

  2. build the test

    make test |tee test.log

  3. run the test

    make runtest |tee runtest.log

Note

cudnn-6.5-linux-R2-RC1 is compatible with caffe, cudnn-6.5-linux-R1 is good. 可以在这个https://groups.google.com/forum/#!forum/caffe-users 里找到这个问题

support python

  1. 安装依赖

    cd $caffe_root/python
    for req in $(cat requirements.txt);do pip install $req; done
    
  2. installl scipy

there is miss requirment scipy this need fortrain compiler you can install it by

  1. install gfortran apt-get install gfortran-4.8
  2. make link due can’t find gfortran ln -s /usr/bin/gfortran-4.8 /usr/bin/gfortan

最简单的办法

apt-get install python-scipy

  1. 添加caffe to python lib

    export PYTHONPATH=/$caffe_root/python:$PYTHONPATH
    
  2. 生成文档

    1. install jekyll

      apt-get install jekyll doxygen texlive-full

深度学习

深度学习与前些年神经网络的区别,那就是网络层数要比以前多了。这样的话功能就大大加强了。

网络一组layer来组成,layer 又由一组node来组成,层与层之间联接是由forword与backwrod连接组成。每一层都solver,以及module. 而这里blobs 就是node. foward 用来把input -> output同时计算出 loss cost,而backword 而是根据loss cost来计算梯度来提取下一步w,b,优化到什么程度为止呢,取决于error 要求和iter numbers.

每一个小的神经网络连接再加上形成大的神经网络,就实现了脑的功能。

Blobs 是由包着数据本身(什么意思?),而数据本身四维的数组(Num,Channels,Height and Width) 有点类似于CUDA的Thread分配。Blobs更像是CUDA Array 的机制。Blobs统一管理CPU与GPU的内存。(n,k,h,w)正好每个线程计算输入都是由Blobs来的。输入传输,利用google proto来进传输。 Google Protocol Buffer 的使用和原理 google 这种机制就其名字一样,(把什么当作?)当作协议包来解析,就像网络包一样,每一个包不需要通用,只要自己能认识自己就行了。就像网络协议一样,只规定了协议包结构。就自然解析就容易了。无非两种TLV,并且进一步利用编码本身实现压缩,并且元编程实现类的自动化定义与实现。并且还支持动态编译JIT,这也就意味着没有只要有源码就行了。

同时Blobs,保存两种数据,一种是Data,一种是diff,简单的说Data是往前传,而diff计算梯度是往后传。

这个是把编码与元编程技术结合起来的。

caffe 这个神经网络还可以snapshotting与resume,这个就非常的方便。

深度网络

本质是一层一层向上抽象的过程。同时一个由无序到有序的过程。但是过程的路径又不指一条,就像人每个人的思维过程也是一样的。所以每一层的每个神经网络的抽象可以不同。并且再加上一顺序就会有各种各样的结果。到这个过程中就像需要有一个像分词库一样的东东。如果只是简单组合就能得到一属性,还是排列才能进行判定, 排列与组合是不同层次的判别路线。

深学习就是在解决如抽象概念这个难题。

caffe流程

caffe的设计原则与自己的原则一样的,分层的模块化的设计。把一个大大的问题不断的breakdown,变成几个已经解决的小问题。 #. 数据格式的转换,目前支持 lmdb,leveldb. #. 定义 network

digraph flow {
    Input->Forward->Output;
    Output->Backword->Input;

}
  1. 定义 solver
  2. training
  3. testing

开发流程添加几个头文件与与源文件。然后实现setup,initial, resharp,forward,backword,然后就注册就行了。

数据的准备

在网络 里主要有 data_paratransform_para .

  1. from database levelDB or LMDB
  2. directly from memory
  3. from files on disk in HDF5
  4. common image formats

而预处理包括,通过指定 TransformationParameterS.

  1. mean subtraction,
  2. scaling
  3. random cropping
  4. mirroring

数据格式

key,value格式,leveldb,lmdm等等就是这种。

hdf5 用来层次化的数据格式,相当于面向对象结构串行化。 如果其看成是例如IP的解析则更容易理解,例如Mongo那种理解,就相当于TLV格式的包结构。 Hierarchical Data format http://en.wikipedia.org/wiki/Hierarchical_Data_Format.

深度学习和并行计算

早期的神经网络,因无法处理两层以上的网络,都是浅层的。目前的深度学习,因采取逐层预训练和全局微调策略,能够实现深层次的网络结构(目前通常需要10层以上的隐含层,才能够取得较好的建模效果),但实际上训练一层的神经网络是非常困难的。这是因为当前的深度学习网络中存在上百万、甚至是上千万的参数需要经过后向反馈来调整,并且深度学习需要大量的训练数据来确保分类和预测的准确性,也就意味着几百万甚至是几千万的输入数据需要运行在前向或者后向反馈中,因此计算量是非常巨大的。另一方面,深度学习由大量相同的、并行的神经元组成,能够并行映射到GPU中,能够提供巨大的计算加速。这里使用NVIDIA公司提供的深度学习平台:CAFFE。 实验已表明,当训练“reference imagenet”时, 并行计算能够获得10倍于intel ivyBridge CPU的加速。

NVIDIA cuDNN 是主要的深度学习GPU加速库,它提供深度学习中常用的操作。比如:卷积、池化、softmax、神经元激活(包括sigmoid、矫正线性器和Hyperbolic tangent ),当然这些函数都支持前向、后向传播,cuDNN主要是在以矩阵相乘的方面擅长,cuDNN特性定数据输出,支持可伸缩的维度定制, dimension ordering, striding and subregions for 对于四维张量。这些可伸缩性允许神经元积分,并且能够避免输入输出转换。

cuDNN是线程安全的,提供基于内容的APi,从而能够支持多线程和共用CUDA线程。使得开发者能够精确地使用多主线程和多GPU,控制库。确保GPU设备总是在一个特殊的主线程中使用。

cuDNN允许深度学习开发者能够掌握当前的状态并且能够把精力集中在应用和机器学习问题上,而不需要写额外的定制代码。cuDNN能够 在Windows和LInux OSes平台上。支持所有的NVIDIA GPU,从低端的GPU,比如Tegra k1 到高端的 Tesla K40. 当开发者使用cuDNN,能够确保得到目前的和未来的高性能,并且得益于GPU特性。

cuDNN是为了深度学习开发者,它非常易用,使得开发者无需知道CUDA。在CAFFE,深度学习使用基于本文的配置文件。使用CAFFE,使用定义神经网络的每一层,制定层的类型(包括数据、卷积和全连接)并且层提供他的输入。并且有类似的配置文件,定义怎样初始化神经网络参数以及训练的重复次数等等。

cudnn

cuda的deeplearning 库

流程本身与CUDA是一样的,数据格式可以改变access pattern可以尽可能利用cache来提高效率。 kernel本身计算模式的改变可以尽可能利用硬件资源。一个算法本身计算量可以大大的减少。 通过thread,L1,L2,register等等,以及 stream, cdn,cnp资源的分配来提高硬件的occupancy.

digraph flow {
    H2D -> "kernel exuection" -> D2H;
}

目前为止,这是CUDA执行模式。各种库无非就在些基础上来进行进一步限定。

或者添加些help函数来实现实现自动的thread分配。并且把一些算法的kernel来实现一下, 并且更加上一些元编程把kernel的实现做一些自动的适配与优化。thrust都是这样干的。

checkCUDNN( cudnnConvolutionForward(cudnnHandle,
                                    &alpha,
                                    srcTensorDesc,
                                    srcData,
                                    filterDesc,
                                    conv.data_d,
                                    convDesc,
                                    algo,
                                    workSpace,
                                    sizeInBytes,
                                    &beta,
                                    dstTensorDesc,
                                    *dstData) );
  1. Convolution 的kerneldnn 自己实现了。
  2. srcTensorDesc,dstTensorDesc, 就是为描述资源的格式与大小方便后存储与对memory 以及kernel的thread的分配。
  3. 主要采用是四维的张量计算
  4. 所谓network其实就是一个cudnnCreate 一个cudaContext而己。用完之后是需要cudaDestroy的。 这样可以把数据保存显存里,然后方便多个kernel之间的计算减少D<=>H之间的传输而己。 可以使用 CUDA annalysis 对其进行分析。
  5. kernel中算法本身需要的参数

其余那就类似于 CUDA runtimeapi 一样,各种各样的get/set以及createhandle之类的东东了。

Theano

Theano

install note

  1. pip install Theano #. pip install numpy #. apt-get install python-scipy
  2. apt-get install libblas-dev #. apt-cache search blas

introduction

theano利用python的语法来实现了自己的语言。这个语言的特别之处,自己实现的用自己的,自己没有实现的就可以直接使用了python的,不过只是一个中间件语言,下层实现还是直接借用CPU与GPU的blas库。并且theano实现还是一个JIT编译器。它的主要特点那就是直接使用利用sympy以及自己的张量符号表达式来直接构造公式,在theano中公式与函数基本上可以直接化等号了。 并且theano还有自己的编译算法,它可以直接打印出依赖图,如何简化自己的逻辑图呢。

既然是语言,就要变量,循环,分支,函数。那theano中是如何实现这些的。

变量 类型两部分,基本类型本身另外那就是结构,例如tensor.dscalar,就是double类型的标量

b w i l f d c byte word int long int float double compex  
scalar vector matrix                        

循环,又分为map/reduce两种。而在theano中采用了scan 来描述。这样是为了能够让theano识别for,只是其返回值,其中update是要function来用,另外是做计算结果来使用的。

分支 对于计算模型循环要远远大于分支,并且在大量的matrix不存在分支模型。所以在计算型的语言中分支会用的比较少,例如CG编程中主要是计算。

函数 直接用表达式来构造函数,但是没有看到其作用域的使用,没有直接声明函数的{}范围,其实直接使用引用传递,与可以实现 多值反回,就可以实现n对n的输出。正常的函数输出是n对1,n对n的输出,那就可以引用传递。在python 可以使用global来实现。 theano中函数声明没有传统语言的方式,直接符号表达式使用来当做函数体。当然这个过程它也会做一些符号计算。帮你做公式推导。

theano.function这个是编译指令,然后返回一个编译后object,就像shaderobject. 函数输入,解决了python中没有引用传递的问题,如果你把变量声明成shared类型,那就是引用传递了。也可以用borrow 的属性来直接使用引用传递。但保存一些python中好的习惯,参数可以有默认的值。格式Param(y,default=1)格式,也可以name/value来赋值。 函数体的可以直接使用输出表达式,也可以用update,given来指定。update 是用来指定如何操作shared变量,而givens,用来变量替换的。 theano这种方式可以复用达到每一条指令的颗粒度,即因为在没有编译之前都是符号表达式。

函数输出可以是多值输出,这可以任意的中间状态输出。

theano 结构

现在明白了theano中对于优化问题的固定的结构,首先declare the variable, then compile the data ,input, outputs, then tain the data; finally look at the results.

declare variable->construct the expression graph-> compile->train->show the results

+theano graph

在调试的时候,我们必须知道什么是graph,包产variable,op等,首先输出的操作数,y.owner.op.name 对于函数输出y.maker.fgraph.outputs,一个函数形式,y.maker.fgraph.inputs是[x, w, b],输入tensorvariable。

好像整个都是以函数的输出就是函数 theano.function{outputs} 中输出的类型就是function,无法得到实际数据。

多次迭代共同改变的是w的值。调节的是x,y 不断的输入,现在明白了为什么w,b是全局变量。

这里的prediction 好像没有什么用,只是预测。

  1. theano学习指南 明天看一下
  2. Intel MKL基础(1)了解MKL、MKL资源 CUDA 是不是有类似的库
  3. matlab

math compiler 公式编译器,原理你把公式写出来,编译器就会把公式化简然后转化为高性能代码来进行计算。因为各个平台都会有各自己的高性能计算库,例如blas,lapack,intel的mkl,还有nv的cuda等等都是有现成了运算库,然后我们需要把算法以及矩阵运算,然后把分块分工,然后分配给这些计算单元并行。看来编译语法分析是重点。自己一定要自己实现一个解析器。

– Main.GangweiLi - 22 Jan 2014

张量计算 这个是theano这个库所主要实现的功能,这个是sympy所没有实现的功能。另外的那就是公式编译器。其通过实现一个图,采用利用图论的最短路径来进行化简。

– Main.GangweiLi - 26 Jan 2014

theano利用自己的内存分配机制,例如share型,一个独立的类型,就像语言一样有register型,对于异构编程的时候,会有对应的内存,例如CPU内存,GPU内存,还有共享区域。

– Main.GangweiLi - 26 Jan 2014

我是不是要实现一门自己的语言,然后把它转化成各种语言,以后我只写我自己的语言,然后再进行转换。

– Main.GangweiLi - 26 Jan 2014

NVCC 这个封装与python自身的那个 destutil 差不多,自己封装一个toolchain for NVCC, 当然要写配置文件,分析配置文件直接使用的是python 的configparser 库,看来自己以后可以直接这个了。

– Main.GangweiLi - 07 Mar 2014

优化 对于不认识的新op是不会进行优化的。

– Main.GangweiLi - 07 Mar 2014

tensorflow

Installation

  1. check GPU Capacity

    ARCH CAPACITY
    Kepler 3.0
    Maxwell 5.0/5.2
    Pas  
    Volta  
  2. install cuda >8.0

    dpkg -i cuda-repo*8.0*
    apt update
    apt install cuda-toolkit
    
  3. install cudnn

    dpkg -i libcudnn-repo*8.0*
    apt update
    apt install libcudnn
    
  4. pip install tensorflow-gpu

_images/overall.png
  1. You can build any kind of customer model and use Theano/TF,as long as it’s differentiable.

无监督学习类假于autoencoders,Restricted Boltzmann Machines

很好的资源库: https://github.com/fendouai/Awesome-TensorFlow-Chinese

不错的基本原理的书: https://github.com/exacity/deeplearningbook-chinese R01 是Tensorflow的中文社区, tensorflow采用数据流图表来描述数学计算。

节点用来表示施加的数学操作,也可以表示数据输入的起点或输出的终点。或者是持久的变量,tensor.

而线用来输入输出之间的关系。

context -> ssession. tensor 来表示数据, 通过变量 维护状态 用feed与fetch 可以为任意操作赋值 与取值。

Placeholder与tf.variable的区别

神经网络库实现的难点,一个是计算的并行化,那另一个那就是variable空间的引用。也就决定了网络的拓扑的如何连线。

如何共享变量

就是通过变量的命名空间,来实现的,http://wiki.jikexueyuan.com/project/tensorflow-zh/how_tos/variable_scope.html

tf.variable_scope 定义一个命名空间,tf.get_variable就在当前空间下搜索该变量。 如果想复用,就得scope.reuse_variables() 来实现

def conv_relu(input,kernel_shape,bias_shape):
     weights = tf.get_variable("weights",kernel_shape,initializer=tf.random_normal_initializer())
     biases  = tf.get_veriable("biases",bias_shape,initializer=tf.random_normal_initializer())
     conv = tf.nn.conv2d(input,weights,strides=[1,1,1,1],padding='SAME')
     return tf.nn.relu(conv,biases)


def my_image_filter(input_images):
    with tf.variable_scope('conv1'):
         # variable will be created with name "conv1/weights","conv1/biases"
         relu1 = conv_relu(input_images,[5,5,32,32],[32])
    with tf.variable_scope('conv2'):
         # variable will be created with name "conv2/weights","conv2/biases"
         return = conv_relu(relu1,[5,5,32,32],[32])


result1 = my_image_filter(image1)
result1 = my_image_filter(image2)
#Raised varibleError(.. conv1/weights already existes)

with tf.variable_scope("image_filters") as scope:
     result1 = my_image_filter(image1)
     scope.reuse_variables()
     result2 = my_image_filter(image2)

tf.variable_op_scope tf.op_scope tf.name_scope tf.variable_scope

tf.concat

t1 = [[1,2,3],[4,5,6]]
t2 = [[7,8,9],[10,11,12]]
#concat_deim 0 表示行,1表示列
tf.concat([t1,t2],0) ==> [[1,2,3,],[4,5,6],[7,8,9],[10,11,12]]
tf.concat([t1,t2],1) ==>[[1,2,3,7,8,9],4,5,6,10,11,12]]
# < 1.0
tf.concat(0,[t1,t2]) ==> [[1,2,3,],[4,5,6],[7,8,9],[10,11,12]]

各种矩阵的形式转换

对于一个默认的列表 [1,2,3,5,6,7,8,9],变成矩阵有几种变法:

  1. [[1,2,3,4,5,6,7,8,9]] 也就是1 * 9 tf.expand_dims(list,0)

#. [[1],[2],[3],[4],[5],[6],[7],[8],[9]] 9* 1 tf.expand_dim(list,1) #. 要变成一个矩阵,就相当于列表的列表,[[1,2,3,4,5,6,7]] 这在tensorflow中叫expand_dims。

网络的基本组成

现在基本上所有神经网络库都采用符号计算来进行拓扑的构造。所以要想研究新的网络拓扑,添加新原语,就得能够添加新的原语。 也就是能够扩展基本原语。

tf.Variable
主要在于一些可训练变量(trainable variables),比如模型的权重(weights,W)或者偏执值(bias); 声明时,必须提供初始值;
tf.placeholder
用于得到传递进来的真实的训练样本: 不必指定初始值,可在运行时,通过 Session.run 的函数的 feed_dict 参数指定;
tf.name_scope
可以用来表示层的概念

tf.run 就相当于求值替换执行。用 eval 用这词就更容易理解了。 并且指定了返回值。

tf.train.Saver
用于何存变量

而矩阵乘法可以用来表征 n*m 的网络连接。 #. 初始化变量 #. 网络拓扑 #. Loss函数 #. 优化方法

global_steps 用于全局的计数器

tensorboard 的用法

http://ischlag.github.io/2016/06/04/how-to-use-tensorboard/

#Tensorflow summaries are essentially logs. And in order to write logs we need a log writer (or what it is called in tensorflow) a SummaryWriter. So for starters, we’ll add the following line before our train loop.

writer = tf.train.SummaryWriter(logs_path, graph=tf.get_default_graph())
#This will create a log folder and save the graph structure. We can now start tensorboard.
tensorboard --logdir=run1:/tmp/tensorflow/ --port 6006

tensorsummary 也是Op,也是需要在session里更新他的。

TensorFlow四种Cross Entropy算法实现和应用

http://www.weibo.com/ttarticle/p/show?id=2309404047468714166594

基本组成

  1. 变量
  • tf.Variable

用点 tensorflow与thenao基本是一致的,都是利用图来构建计算模型,这些在python里实现,而真正的计算独立来实现的。 python 只是相当于一个控制台而己。

这样结构有点类似于符号计算的味道了。 在tensorflow.

变量就相当于符号。 各种placeholader,以及各种运算都符号化了。

这也正是编程语言的下一个趋势,算法的描述。

先构建computation graph,然后初始化,再开始运行。

根据神经网络的结构来,

源码解读

R02 已经做了源码的解读,基本实现原理

  1. 脚本的语言与c/c++ 的接口用 SWIG来实现,这就意味着支持多种脚本
  2. 构建工具,
    • linux 采用bazel 的并行构建工具,每一个目录为一个包为基本单位,进行依赖计算。
    • Windows 也可以用 CMake 来时行编译
  3. 矩阵计算采用EIGEN来进行处理或者调用Nvidia-cublas来加速计算
  4. 结构化数据存储结构来用protobuf来定义

基本步骤

  1. Create the Model

    x = tf.placeholder(tf.float32,[None,784])
    W = tf.Variable(tf.zeros([784,10]))
    b = tf.Variable(tf.zeros([10]))
    y = tf.matmul(x,W) + b
    
  2. Define Target

    y_ = tf.placeholder(tf.float32,[None,10])
    
  3. Define Loss function and Optimizer

    cross_entropy = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(label=y_,logits=y))
    train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
    
  4. Define the Session and Initialise Variable

    sess = tf.InteractiveSession()
    tf.global_variables_initializer().run()
    
  5. Train the Model

    for _ in range(1000):
        batch_xs,batch_ys = mnist.train.next_batch(100)
        sess.run(train_step,feed_dict={x,batch_xs,y_:batch_ys})
    
  6. Test Trained Model

    correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
    accuracy = tf.readuce_mean(tf.cast(correct_prediction,tf.float32))
    print(sess.run(accuracy,feed_dict={x:mnist.test.images,y_:mnist.test.labels}))
    

符号计算

通过符号计算,来设定计算的边界,来进行尽可能的优化。可以很方便的进行序列化。

Session的实现

实现原理 采用的是传递闭包原理。

http://www.cnblogs.com/yao62995/p/5773578.html

同时多线程实现了类似于Unreal中那样运行库。

op的实现

CPU 用EIGEN来实现,或者其他库加速库来实现。

References

https://github.com/Microsoft/CNTK 安装需要额外安装一个anaconda python 就行了。 同时用VS 来做开发,在 tools.options>python 添加新环境变量,同时在工程文件中使用右键选择新的环境变量就行了。

  1. 安装VS2017 并选择 Data Processing 模块。
  2. pip install cntk from https://docs.microsoft.com/en-us/cognitive-toolkit/Setup-Windows-Python?tabs=cntkpy22
  3. pip install keras
  4. pip install tensorflow-gpu
  5. set the backend of keras set KERAS_BACKEND=cntk

setup on Azure

  1. Deploy CNTK Azure web API
  2. Data Science Virtual Machine

使用的基本步骤,那就是建立网络拓扑,指定参数训练,输入适配。

cntk的主要用途

  1. Feed forward
  2. CNN
  3. RNN
  4. LSTM
  5. Sequence-to-Sequence

用法也应该类似于CUDA了,有自己的API来指定结构。

有两种方式,在python里,是靠重载几个子命令来实现网络拓扑的,例如linear_layer,input_variable,dense_layer,fully_connected_classifier_net等等。

采用方式类似于theano的方式,利用图来构造网络结构。 所以也就是构造图的过程。 利用input,parameter,以及基本函数来当做原语来指定输入输出。

torch

主要是相当于GPU的版本的numpy.

torch 采用 lua 来做其脚本,lua 短小精炼,集C的语法,python的缩进语法,javascript似的函数闭包。

包管理用 Luarocks 例如 i .. code-block:: bash

luarocks install XXXX

傻瓜式安装,在运行的时候,可能会遇到GPU driver的匹配问题,重启一下就好了。同时由于 torch 最新支持的cudnn5. 现在机器上的cudnn6. 两个版本改动不大。 直接发把库名与版本号检查改大就行了。

# install/share/lua/5.1/cudnn/ffi.lua
local CUDNN_PATH = os.getenv('CUDNN_PATH')
if CUDNN_PATH then
    io.stderr:write('Found Environment variable CUDNN_PATH = ' .. CUDNN_PATH)
    cudnn.C = ffi.load(CUDNN_PATH)
else

    -- local libnames = {'libcudnn.so.5', 'libcudnn.5.dylib', 'cudnn64_5.dll'}
    local libnames = {'libcudnn.so.6', 'libcudnn.6.dylib', 'cudnn64_6.dll'}
    local ok = false
    for i=1,#libnames do
        ok = pcall(function () cudnn.C = ffi.load(libnames[i]) end)
        if ok then break; end
    end

 ------------------
 -- check cuDNN version
 cudnn.version = tonumber(cudnn.C.cudnnGetVersion())
 --if cudnn.version < 5005 or cudnn.version >= 6000 then
 if cudnn.version < 5005 or cudnn.version >= 7000 then
    error('These bindings are for CUDNN 5.x (5005 <= cudnn.version > 7000) , '
         .. 'while the loaded CuDNN is version: ' .. cudnn.version
            .. '  \nAre you using an older or newer version of CuDNN?')
 end

pytorch

这个是由Facebook 重写了一遍的torch, torch 本身底层用C来实现,通常可以把PyTorch当做numpy的替代。 而torch lib 又分为

TH = TorcH
THC = TorcH Cuda
THCS = TorcH Cuda Sparse
THCUNN = TorcH CUda Neural Network (see cunn)
THD = TorcH Distributed
THNN = TorcH Neural Network
THS = TorcH Sparse
_images/overall1.png
  1. tensor的结构与numpy的都是通用互转的。

pytorch 动态指的其使用命令模式,而不是符号式。这样好处在于动态修改网络。这样的好处,就像传统的编码方式,动态性就比较好。并且传统的堆栈式调试都可以派上用场了。

对于 PyTorch 来说,Chainer 是一个先行者。PyTorch 主要受三个框架启发。在 Torch 社区中,Twitter 的某些研究人员构建了名为 Autograd 的辅助软件包,它实际上是基于 Python 社区中的 Autograd。与 Chainer 类似,Autograd 和 Torch Autograd 都采用了一种称为基于磁带(tape-based)的自动分化技术:就是说,你有一个磁带式录音机来记录你所执行的操作,然后它向后重放,来计算你的梯度。这是除了 PyTorch 和 Chainer 之外的任何其他主要框架都不具备的技术。所有其他框架都使用所谓的静态计算图,即用户构建一个图,然后将该图传递给由框架提供的执行引擎,然后框架会提前分析并执行它。

这些是两种不同的技术。基于磁带的差异化使您更容易调试,并为您提供更强大的某些功能(例如,动态神经网络)。基于静态图形的方法使您可以轻松部署到移动设备,更容易部署到异乎寻常的架构,提前执行编译器技术的能力等等。

并在Facebook内部,PyTorch用于所有研究项目,Caffe2用于所有产品项目。两者模型是可以相互转换的。

train_set = torch.FloatTensor(training_set)

工作流程

  1. 建立网络模型
  2. 数据结构建模->tensor
  3. 各种tensor之间的适配
    1. torch.squeeze(),torch.unsqueeze()
    2. torch.expand(),torch.cat()
  4. 定义优化器。

tensor基本的数学运算

torch.addcdiv

\[out_i = tensor_i + value \times \frac{tensor1_i}{tensor2_i}\]

torchvision.transforms

常用 image变换,并且chainup.

quick tutoiral

PyTorch 中文网 .. image:: /Stage_3/pytorch/dynamic_graph.gif

内存管理

也就是各种变量的使用,以及作用域。而对于深度网络的框架主要是网络参数的更新,这些参数需要与独立出来,能够加载。

变量

基本的数据结构张量(Tensor).

各种运算

  1. 各种sum的计算,可以看作是group的功能,理解为对某一行或某一例的求和吧。
  2. 其他的一些逐点计算,sqrt,还有一些那就是求导计算。
  3. 关键是乘法,有多种
    • 数乘 (变相的矩阵乘)
    • 内积 也就是标量乘 \(a*b = |a| |b| * cos\)
    • 外积 也就是点乘。 *
    • 混合积
    • 范数

n对于n的数乘就是矩阵乘。

对于矩阵试编程中,随时变量实现。例如

temp = a*b
c = temp * 1
d = temp * 1.5
e = temp * 2
# implment in matrix mul
matrix_base = torch.stack[[temp] * 3,dim=0]
matrix_c = torch.sensor([c,d,e])
matrix = matrix_base *matrix_c

source code reading

torch.nn.module

整个网络层的基本结构,参数的存放,然后就是foward与backword的计算。 其他就是一些辅助函数了。就像最基本的类型

class layer :
  def __init__():
      self.W
      self.B

  def foward():
      return self.active(self.W*self.X +self.B)
  def cost():
      error = distance(self.foward(),origina_data_force)

  def backwoard():
      self.W = self.W + xxxxx

这个是网络拓扑的根结构,基本结构也就是dict,并且module是不可以不断嵌入的。

  1. addModules

    code-block:: python

    self._modules[‘module_name’] = module

#. parameters. 这个函数variable的一种封装。因为一个模块的parameter在迭代中才会更新。 当做parameters的变量传给module时,会自动变成其参数的一部分。 核心是 __init__ 在这里,生成网络。

  1. 然后是其forward函数。需要自己实现。

  2. 其核心那就是那个__call__ 的实现。

    def __call__(self, *input, **kwargs):
      for hook in self._forward_pre_hooks.values():
          hook(self, input)
      result = self.forward(*input, **kwargs)
      for hook in self._forward_hooks.values():
          hook_result = hook(self, input, result)
          if hook_result is not None:
              raise RuntimeError(
                  "forward hooks should never return any values, but '{}'"
                  "didn't return None".format(hook))
      if len(self._backward_hooks) > 0:
          var = result
          while not isinstance(var, Variable):
              if isinstance(var, dict):
                  var = next((v for v in var.values() if isinstance(v, Variable)))
              else:
                  var = var[0]
          grad_fn = var.grad_fn
          if grad_fn is not None:
              for hook in self._backward_hooks.values():
                  wrapper = functools.partial(hook, self)
                  functools.update_wrapper(wrapper, hook)
                  grad_fn.register_hook(wrapper)
    return result
    

optim

for input,target in dataset:
     optimizer.zero_grad()
     output=model(input)
     loss = loss_fn(output,target)
     loss.backword()
     optimizer.step()

各种优化算法的原理与区别

基本上都是采用的迭代的方法,核心 \(\Theta = \Theta - \alpha \cdot \triangledown_\Theta J(\Theta)\)

这种方法,容易停在鞍点,

Momentum算法,同时观察历史梯度 \(v_{t}\)

\[v_{t} = \gamma \cdot v_{t-1} + \alpha \cdot \triangledown_\Theta J(\Theta) \Theta = \Theta -v_{t}\]

Adagrad

是对learningrate的改变,我们采用频率较低参数采用较大的更新,相反,频率较高的参数采用较小的更新。采用累加之前的所有梯度平方的方法,这个造成训练的中后期,分母上梯度累加变大,就会造成梯度趋近于0,使得训练提前结束。

RMSprop的方法

采用计算对应的平均值,因此可缓解adagrad算法学习率下降较快的问题。

Adam

利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率,使得参数比较平稳。

_images/optims_1.gif

损失平面等高线随时间的变化情况

_images/optims_2.gif

不同算法在鞍点处的行为比较

http://shuokay.com/2016/06/11/optimization/

有两个超参数beta1,beta2来用计算指数移动均值的时候使用。是不是股票中移动均线的方法来计算。

beta1 : 一阶矩估计的指数衰减率 beta2 :二阶矩估计的指数衰减率

epsilon: 该参数是非常小的数,主要为防止实现中除零10E-8.

L-BFGS算法

无约束最小化,http://www.hankcs.com/ml/l-bfgs.html,解决了计算海森矩阵的烦恼。但是吃内存,L-BFGS 就是改进内存的使用用的BFGS算法。

how to save the model

  1. torch.save(self.G.state_dict(),”model path”)

onnx

from torch.autograd import Variable
import torch.onnx
import torchvision

dummy_input = Variable(torch.randn(10,3,224,224)).cuda()
model = torchvision.models.alexnet(pretrained=True).cuda()
#。 alexnet.proro caffe 二制model,verbose会打印出可读信息
torch.onnx.export(model,dummy_input,"alexnet.proto",verbose=True)



#import model in caffe

model = onnx.load('alexnet.proto')

#Check that the IR is well formed
onnx.checker.check_model(model)

#print a human readdable represnetation of the graph
onnx.helper.printable_graph(model.graph)

符号推导

torch与 numpy不同的地方,很大一部分原因那就是对微分的符号推导的完美实现的。

通过对于一个正常的tensor添加一个wraper,就形成了,就变成了符号,但是又起了Variable的类型,这难免给你一种误解,那就是用蓝色笔来红色的红字。如果把其叫符号,不容易误解了。torch并没有实现符号推导的大部分功能,只实现了微分推导的功能,并且将其推导到了极致。但是它要求推导只能是标量,一次只能对一个Y,对多个x 求导。

一旦把 tensor-> Variable,就是意味着变成符号。但是其类型还保持原来的样子,其实就是利用链式求导法,在v.grad里实现了所有函数操作,abs,+/- tan等等操作微分求法。

由于保存了长链,需要占用大量的内存,所以默认情况下,求导只用一次,并且用完就扔了。如果二次利用就是添加retain_variables=True.

https://sherlockliao.github.io/2017/07/10/backward/, 并且backword之后,可以得到每一个因变量在此处的导数。 而且对于为什么backword可以传参数,就是为解决对tensor对tensor求导的问题。

相当于 先计算l =torch.sum(y*w),然后求l对能够影响到Y的所有变量x的导数。

https://zhuanlan.zhihu.com/p/29923090

import torch as t
from torch.autograd import Variable as v

a = t.ones(2,2)
# [1,1]
# [1,1]
x = v(a,requried_grad=True)
# [x00,x01]
# [x10,x11]

Step

整个优化迭代就在这个step函数中,

就是实现关键的 \(W_n=W_{n-1} + \triangledown\theta\)

Tensorrt

基本概念

并且所有layer与Tensor都会有名字,然后通过其名字来查找。

network definition

Layer

Tensor
tensorrt支持的格式最多8维。最基本的格式N(P_1 P_2 …) CHW. 也就是最少的就是NCHW。采用的是按列排序。 最外面是Batch的size. 最基本的infer.tensor作为输入输出结构。

而看到,GetNetBatchSize,GetNetWidth,就是指这些。

_images/DL_Deloy_flow.png
WorkSpace
用于指定layer exectuion时,所需要的临时空间大小,并且这个大小layers之间共享的。 相当于运行之间heap大小。你可以通过 getWorkspaceSize()来得到。

最基本的workflow

https://github.com/LitLeo/TensorRT_Tutorial/blob/master/TensorRT_2.1.0_User_Guide.mdjjjjjjjjjjjjjjjjjjjj 使用TensorRT包括两部步骤(1)打开冰箱;(2)把大象装进去:

build阶段,TensorRT进行网络定义、执行优化并生成推理引擎 execution阶段,需要将input和output在GPU上开辟空间并将input传输到GPU上,调用推理接口得到output结果,再将结果拷贝回host端。 build阶段比较耗时间,特别是在嵌入式平台上。所以典型的使用方式就是将build后的引擎序列化(序列化后可写到硬盘里)供以后使用。

  1. 读网络定义

  2. buildnet

  3. optimize

  4. provide intput/output. 默认的输入输出已经是host memory了。

  5. create engine context

  6. do infer

    context.execute(batchSize,buffers);
    //or
    context.enqueue(batchSize,buffers,stream,nullptr);
    

输入输出,都在buffers 里,执行完,直接把buffers中ouputbuffer的Tensor结构copy回去就行了。

//建立一个builder+log 来实现各种framework的转换
IBuilder * builder = createInferBuilder(*plogger)

INetworkDefinition  *network = build->createNetwork();

主要用来推理,并且 并且能够层级融合优化。 #. 合并 tensor及layers. #. 参数的调优

_images/tensorrt_optimize.png _images/tensorrt_proformance.png

现在已经可以做到7ms的时延了。

这种编程模式已经进化了,加载了网络图的定义,然后再加载参数,然后执行,这不就是新行的加编程模型了。