美文网首页
Blob、Layer and Nets:anatomy of a

Blob、Layer and Nets:anatomy of a

作者: 北方核桃 | 来源:发表于2018-05-23 10:59 被阅读0次

    学习caffe官网教程,粗略翻译一下供以后参考。


    Blob存储和传递(数据)

    Blob是封装后的数据,用来在Caffe中处理和传递数据,并且可以在CPU和GPU之间同步数据。Blob结构从数学上来讲,是一个N维数组,按照C-contiguous方式存储数据(C-contiguous fashion指内存存储是连续的、不间断存储的)。

    Caffe通过Blob来存储和传递数据,Blob提供了统一的内存接口来保存数据,例如图像数据(batches of images)、模型参数和优化模型时的导数等。

    Blob隐藏了计算及内部处理细节,实现了按需从CPU到GPU同步数据。主机和设备间的内存按需分配以提高内存使用效率。

    约定用于处理图像数据的Blob的维度是:N × K(channel) × H(height) × W(width). Blob内存是按行优先方式(row-major)存储的,所以最下边和最右边(last/rightmost)的维度变化很快。例如:一个4维Blob(n,k,h,w)的物理内存地址为:((nK+k)H+h)*W+w。

    • N是一次处理数据的大小,对计算和设备处理来说,批量处理数据能获得更好的输出。
    • K是特征维度,例如:对RGB图像,K=3。

    尽管Caffe示例中许多Blob的图像应用都是4维的,但Blob对非图像应用也是完全有效的。例如,如果你只需要像传统的多层感知器那样的全连接网络,可以使用2维Blob(N,D)并且调用InnerProductLayer。

    参数Blob维度根据网络层的类型和配置而有所不同。对3输入,96个11*11滤波器(filter)的卷积层,其Blob是96 × 3 × 11 × 11。对1024个输入通道(input channel),1000个输出通道(output channel)的内部的全连接层,其Blob为:1000 × 1024。

    对于自定义数据,可能有必要写自己的输入准备代码或数据层。然而,一旦数据搞定。蹭的模块化将完成剩下的工作。


    实现细节

    Blob在内存中存储了两块数据:datadiffdata是我们传递的正常数据,diff是网络计算的梯度。

    此外,由于实际值可以存储在CPU和GPU上,因此有两种不同的方式来处理他们:the const way:不改变值;the mutable way:改变值。

    const Dtype* cpu_data() const; // the const way
    Dtype* mutable_cpu_data(); // the mutable way
    // 对GPU和diff也是一样的
    

    这样设计的原因是Blob使用SyncedMem类在CPU和GPU之间同步数据,以隐藏实现细节并最小化数据传输量。一个经验法则是如果不需要改变值的话总是使用const来调用,并且永远不要在自己的对象中存储指针。每次使用Blob时,调用函数来获得指针,因为SynceMen将需要这个来确定何时复制数据。

    在实践中,当GPU存在时,将数据从磁盘加载到CPU代码中的Blob,调用内核设备来执行GPU计算,并将Blob运送到下一层,在保持高层性能的同时忽略低层细节、只要所有层都有GPU的实现,所有中间数据和梯度都会保存在GPU中。

    如果想查看Blob何时复制数据,下面是解说示例。

    //Assuming that dat aera on the CPU initialluy, and we have a blob.
    
    const Dtype* foo
    Dtype* bar;
    foo = blob.gpu_data();        //data copied cpu->gpu.
    foo = blob.cpu_data();        //no data copied since both have up-to-data contens.
    bar = blob.mutable_gpu_data();        //no data copied.
    
    //... some operations ...
    
    bar = blob.mutable_gpu_data();        //no data copied when we are still on GPU
    foo = blob.cpu_data();        //data copied gpu->cpu, since the gpu side has moditied the data
    foo = blob.gpu_data();        //no data copied since both have up-to-data contens
    bar = blob.mutable_cpu_data();        // still no data copied.
    bar = blob.mutable_gpu_data();        // data copied cpu->gpu.
    bar = blob.mutable_cpu_data();        // data copied gpu->cpu.
    

    Layer计算和连接

    Layer是Caffe最重要的部分,也是计算的基本单元,Layer层中可以进行很多运算:

    convolve filters 卷积层
    pool 池化层
    inner products 内积运算
    apply nonlinearities like rectified-linear and sigmoid 进行非线性映射,例如relu函数和sigmoid函数
    normalize 归一化
    load data 载入数据
    compute losses like softmax and hinge** 计算损失函数,例如softmax和hinge

    可以在Layer页面查看所有运算。包括了所有深度学习任务所涉及的最先进的类型。

    bottom输入,top输出
    每个层定义了了三种重要的计算:初始化(setup)、前向迭代(forward)、后向迭代(backward)。
    • setup:模型初始化时初始化Layer及其连接。
    • forward:从bottom接受输入,进行计算后,从top输出。
    • backward:从top获得输出,计算梯度,并传递到bottom。
      更具体的说,将会实现两个前向和后向功能,一个用于CPU,一个用于GPU。如果没有实现GPU版本,Layer将会作为备份退回到CPU功能。虽然会带来而外的输出传输成本,但如果想快速实验,可能会派上用场。

    Layer在整个网络操作中有两个主要责任:前向通道获得输入,计算产生输出;反向通道获得输出的梯度,和关于参数参数的梯度传递给输入,进而传播到更早的层次(此句翻译还需斟酌)。这些传播只是每层前向和后向的结构。

    开发自定义层只需很少的工作量,主要是修改网络结构和模块代码;为层定义setup、forward、backward后就可以加入到网络中了。


    Net定义和操作

    网络通过组合和自动差分定义了一个函数,每层输出的组合完成计算给定任务的功能,每层后向迭代的组合从损失中计算梯度来学习任务。Caffe模型是端到端的机器学习引擎。

    网络是一组连接在计算图中的层------一个有向无环图(DAG)。Caffe记录所有层的DAG来保证前向传播和反向传播的正确性。一个典型的网络始于数据层,该层从磁盘载入数据,终于损失层,该层计算诸如分类和重建等任务。

    Net被定义为一组层及其连接,用一种明文建模语言描述(a plaintext modeling language)。一个简单的逻辑分类回归器如下图所示。


    逻辑分类回归器

    定义如下

    name: "LogReg"
    layer {
      name: "mnist"
      type: "Data"
      top: "data"
      top: "label"
      data_param {
        source: "input_leveldb"
        batch_size: 64
      }
    }
    layer {
      name: "ip"
      type: "InnerProduct"
      bottom: "data"
      top: "ip"
      inner_product_param {
        num_output: 2
      }
    }
    layer {
      name: "loss"
      type: "SoftmaxWithLoss"
      bottom: "ip"
      bottom: "label"
      top: "loss"
    }
    

    模型通过Net::Init()初始化。初始化主要做两件事:通过创建Blobs和Layers来构建所有DAG;然后调用层的SetUp()函数。还做一些其他的记录,如验证所有网络结构的正确性。此外,初始化期间网络通过日志记录其初始化过程:

    I0902 22:52:17.931977 2079114000 net.cpp:39] Initializing net from parameters:
    name: "LogReg"
    [...model prototxt printout...]
    # construct the network layer-by-layer
    I0902 22:52:17.932152 2079114000 net.cpp:67] Creating Layer mnist
    I0902 22:52:17.932165 2079114000 net.cpp:356] mnist -> data
    I0902 22:52:17.932188 2079114000 net.cpp:356] mnist -> label
    I0902 22:52:17.932200 2079114000 net.cpp:96] Setting up mnist
    I0902 22:52:17.935807 2079114000 data_layer.cpp:135] Opening leveldb input_leveldb
    I0902 22:52:17.937155 2079114000 data_layer.cpp:195] output data size: 64,1,28,28
    I0902 22:52:17.938570 2079114000 net.cpp:103] Top shape: 64 1 28 28 (50176)
    I0902 22:52:17.938593 2079114000 net.cpp:103] Top shape: 64 (64)
    I0902 22:52:17.938611 2079114000 net.cpp:67] Creating Layer ip
    I0902 22:52:17.938617 2079114000 net.cpp:394] ip <- data
    I0902 22:52:17.939177 2079114000 net.cpp:356] ip -> ip
    I0902 22:52:17.939196 2079114000 net.cpp:96] Setting up ip
    I0902 22:52:17.940289 2079114000 net.cpp:103] Top shape: 64 2 (128)
    I0902 22:52:17.941270 2079114000 net.cpp:67] Creating Layer loss
    I0902 22:52:17.941305 2079114000 net.cpp:394] loss <- ip
    I0902 22:52:17.941314 2079114000 net.cpp:394] loss <- label
    I0902 22:52:17.941323 2079114000 net.cpp:356] loss -> loss
    # set up the loss and configure the backward pass
    I0902 22:52:17.941328 2079114000 net.cpp:96] Setting up loss
    I0902 22:52:17.941328 2079114000 net.cpp:103] Top shape: (1)
    I0902 22:52:17.941329 2079114000 net.cpp:109]     with loss weight 1
    I0902 22:52:17.941779 2079114000 net.cpp:170] loss needs backward computation.
    I0902 22:52:17.941787 2079114000 net.cpp:170] ip needs backward computation.
    I0902 22:52:17.941794 2079114000 net.cpp:172] mnist does not need backward computation.
    # determine outputs
    I0902 22:52:17.941800 2079114000 net.cpp:208] This network produces output loss
    # finish initialization and report memory usage
    I0902 22:52:17.941810 2079114000 net.cpp:467] Collecting Learning Rate and Weight Decay.
    I0902 22:52:17.941818 2079114000 net.cpp:219] Network initialization done.
    I0902 22:52:17.941824 2079114000 net.cpp:220] Memory required for data: 201476
    

    注意网络的构建设备是未知的,回想先前的解释,Blob和Layer在模型定义中隐藏了实现细节。构建完成后,网络通过设置在Caffe::mode()中定义的Caffe::set_mode()来运行在CPU或GPU上。Layer在CPU和GPU模式下运算的结果是一致的。CPU和GPU和实现无缝切换,与模型定义无关。


    model格式

    模型在prototxt中定义,而学习模型被序列化为binaryproto,位于***.caffemodel文件中。模型格式由caffe.proto中的protobug模式定义。

    相关文章

      网友评论

          本文标题:Blob、Layer and Nets:anatomy of a

          本文链接:https://www.haomeiwen.com/subject/owqqjftx.html