Caffe、Theano、MXNet、PaddlePaddle源码分析

目录

 

Caffe

基本概念

caffe 和 caffe2在构建网络上的区别  

Lightning Memory-Mapped Database (LMDB)

Theano

scan函数

DeepCopyOp

ViewOp

MXNet

logging.h文件

KVStore: 多设备间的数据交互

PaddlePaddle

topk

logits


Caffe

基本概念

caffe中一个模型由多个层(layer)构成,每一层又由许多参数组成。所有的参数都定义在caffe.proto这个文件中。

层有很多种类型,比如Data、Convolution、Pooling等,层之间的数据流动是以Blobs的方式进行。

top或bottom: 每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个 top或多个bottom,表示有多个blobs数据的输入和输出。

layer {
  name: "cifar"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mean_file: "examples/cifar10/mean.binaryproto"
  }
  data_param {
    source: "examples/cifar10/cifar10_train_lmdb"
    batch_size: 100
    backend: LMDB
  }
}

name: 表示该层的名称,可随意取

type: 层类型,如果是Data,表示数据来源于LevelDB或LMDB。根据数据的来源不同,数据层的类型也不同(后面会详细阐述)。一般在练习的时候,我们都是采 用的LevelDB或LMDB数据,因此层类型设置为Data。

top或bottom: 每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个 top或多个bottom,表示有多个blobs数据的输入和输出。

data 与 label: 在数据层中,至少有一个命名为data的top。如果有第二个top,一般命名为label。 这种(data,label)配对是分类模型所必需的。

include: 一般训练的时候和测试的时候,模型的层是不一样的。该层(layer)是属于训练阶段的层,还是属于测试阶段的层,需要用include来指定。如果没有include参数,则表示该层既在训练模型中,又在测试模型中。

Transformations: 数据的预处理,可以将数据变换到定义的范围内。如设置scale为0.00390625,实际上就是1/255, 即将输入数据由0-255归一化到0-1之间

caffe 和 caffe2在构建网络上的区别  

 caffe 的网络由粒度较粗的layer组成,即每个layer的 weight 和 bias 都以layer级别存储

 caffe2 的网络组成使用 operator 方式,由更细粒度的 operator 组合而成。

Lightning Memory-Mapped Database (LMDB)

LMDB是基于二叉树的数据库管理库,建模基于伯克利数据库的应用程序接口,但做了大幅精简。整个数据库都是内存映射型的,所有数据获取返回数据都是直接从映射的内存中返回,所以获取数据时没有malloc或memcpy发生。因此该数据库仍是非常简单的,因为它不需要自己的页面缓存层,并且非常高效、省内存。它在语义上完全符合ACID(原子性、一致性、隔离性、持久性)。当内存映射为只读时,数据库完整性不会被应用程序的迷失指针写破坏。该库也是线程可见的,支持来自多进程/线程的并发读/写访问。数据页使用写时复制策略,故没有活动数据页被覆盖写入。这也提供了保护机制,经历系统崩溃后不需要特殊恢复过程。写入过程为完全串行的;一次只有一个写会话是活动的,这保证了写入者不可能死锁。数据库结构是多个版本,所以读出者运行时不加锁。写入这不会阻塞读出者,读出者也不会阻塞写入者。不像其他熟知的数据库机制(使用写前会话日志或数据仅追加写),LMDB操作时不需要保持会话。前面两种都需要周期性地检查或者压缩他们的日志或数据库文件,否则会无限增长。LMDB记录数据库内的空页面,在新的写入操作时重用他们,所以正常使用时数据库尺寸不会无限增加。内存映射可以用作只读映射或读写映射。默认为只读映射,这提供了对破坏完全的免疫力。使用读写模式提供了更高的写性能,但增加了被恶意写入破坏数据库的可能性。当然如果你的应用代码是已知无bug的,那么这不是个严重的问题。

Theano

在theano编程中,Graph是指导theano如何对变量进行操作的唯一途径,theano变量和theano Ops(操作)是Graph的两个基本构成元素。Graph只能由theano变量(包括shared变量)或常数组成。

scan函数

scan是theano中构建循环Graph的方法,函数声明如下:  

theano.scan(fn, sequences=None, outputs_info=None, non_sequences=None, n_steps=None, truncate_gradient=-1, go_backwards=False, mode=None, name=None, profile=False, allow_gc=None, strict=False)  

fn:函数类型,scan的一步执行。除了outputs_info,fn可以返回sequences变量的更新updates。fn的输入变量顺序为sequences中的变量,outputs_info的变量,non_sequences中的变量。如果使用了taps,则按照taps给fn喂变量,taps的详细介绍会在后面的例子中给出。  

sequences:scan进行迭代的变量;scan会在T.arange()生成的list上遍历,例如下面的polynomial 例子。  

outputs_info:初始化fn的输出变量,和输出的shape一致;如果初始化值设为None表示这个变量不需要初始值。  

non_sequences:fn函数用到的其他变量,迭代过程中不可改变(unchange)。  

n_steps:fn的迭代次数。

DeepCopyOp

We have an internal Op called DeepCopyOp. It is used to make sure we respect the user vs Theano memory region as described in the tutorial. Theano has a Python implementation that calls the object’s copy() or deepcopy() method for Theano types for which it does not know how to generate C code.

You can implement c_code for this op. You register it like this:

theano.compile.ops.register_deep_copy_op_c_code(YOUR_TYPE_CLASS, THE_C_CODE, version=())

In your C code, you should use %(iname)s and %(oname)s to represent the C variable names of the DeepCopyOp input and output respectively. See an example for the type GpuArrayType (GPU array) in the file theano/gpuarray/type.py. The version parameter is what is returned by DeepCopyOp.c_code_cache_version(). By default, it will recompile the c code for each process.

ViewOp

We have an internal Op called ViewOp. It is used for some verification of inplace/view Ops. Its C implementation increments and decrements Python reference counts, and thus only works with Python objects. If your new type represents Python objects, you should tell ViewOp to generate C code when working with this type, as otherwise it will use Python code instead. This is achieved by calling:

theano.compile.ops.register_view_op_c_code(YOUR_TYPE_CLASS, THE_C_CODE, version=())

In your C code, you should use %(iname)s and %(oname)s to represent the C variable names of the ViewOp input and output respectively. See an example for the type GpuArrayType (GPU array) in the file thean/gpuarray/type.py. The version parameter is what is returned by ViewOp.c_code_cache_version(). By default, it will recompile the c code for each process.

MXNet

logging.h文件

DateLogger  

直接由无参数函数 HumanDate() 获取以冒号分割的当前系统时间,具体格式为 HH:MM:SS 

LogMessage

构造函数有两个参数 一个为文件名,一个为行号,一般由编译器宏 __FILE__ __LINE__ 给出,其构造函数输出包装后的 DateLogger 格式为  [HH:MM:SS]  FILE: LINE : 析构函数输出 "\n".作为换行结束,同时拷贝构造函数和操作符= 用private修饰,用以禁止对该类的对象的拷贝和复制。

CustomLogMessage

是一个留出用户接口的类,只实现了LogMessage的构造函数类似的功能,至于析构函数和静态的Log函数没有具体实现,留给用户再具体使用是实现Log自定义输出。也就是说该类是留给二次开发的开发者使用的。

 LogMessageFatal

与上面的LogMessage类似,构造函数完全一致。析构函数多了处理异常和出错时的栈空间调用信息的输出,同时析构函数最后有abort()系统函数调用,用以终止进程:要么catch异常,要么abort()进程。Fatal函数的不可修复性, 注定了他的命运只能abort(); 该类和LogMessage对于拷贝构造和=运算符重载的处理也是一致的:私有化,防止了对该类的随意复用。

其余部分为模拟 google glog的宏

其中 LOG(INFO) LOG(WARNING) LOG(ERROR) 都是向 LogMessage的stream 中输出

LOG(FATAL) 是向 LogMessageFatal 的stream中输出信息

宏的拼写过程大概是

LOG(INFO)    => LOG_INFO().stream()   => dmlc::LogMessage(__FILE__, __LINE__).stream()

LOG(FATAL)  => LOG_FATAL().stream() => dmlc::LogMessageFatal(__FILE__, __LINE__).stream()

KVStore: 多设备间的数据交互

MXNet提供一个分布式的key-value存储来进行数据交换。它主要有两个函数,

push: 将key-value对从一个设备push进存储 
pull:将某个key上的值从存储中pull出来此外,KVStore还接受自定义的更新函数来控制收到的值如何写入到存储中。最后KVStore提供数种包含最终一致性模型和顺序一致性模型在内的数据一致性模型。

KVStore的实现是基于参数服务器。但它跟前面的工作有两个显著的区别。  我们通过引擎来管理数据一致性,这使得参数服务器的实现变得相当简单,同时使得KVStore的运算可以无缝的与其他结合在一起。 我们使用一个两层的通讯结构,原理如下图所示。第一层的服务器管理单机内部的多个设备之间的通讯。第二层服务器则管理机器之间通过网络的通讯。第一层的服务器在与第二层通讯前可能合并设备之间的数据来降低网络带宽消费。同时考虑到机器内和外通讯带宽和延时的不同性,我们可以对其使用不同的一致性模型。例如第一层我们用强的一致性模型,而第二层我们则使用弱的一致性模型来减少同步开销。 

PaddlePaddle

topk

此OP用于查找输入Tensor的最后一维的前k个最大项,返回它们的值和索引。 如果输入是1-D Tensor,则找到Tensor的前k个最大项,并输出前k个最大项的值和索引。如果输入是更高阶的Tensor,则该OP会基于最后一维计算前k项。

logits

TensorFlow、PyTorch等框架也有

是未进入softmax的概率,一般是全连接层的输出,softmax的输入。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值