Blob、Layer and Nets:anatomy of a Caffe model


学习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模式定义。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容