Caffe2 的基本数据结构(Basics of Caffe2 - Workspaces, Operators, and Nets)[4]

这篇文章主要介绍Caffe2的基本数据结构:

  • Workspaces
  • Operators
  • Nets

在开始之前最好先阅读以下Intro Turorial
首先,导入caffe2。其中coreworksapce模块,这是必须的两个模块。如果你要使用Caffe2生成的protocol buffers,那么你也需要从caffe2_pb2中导入caffe2_pb2模块。

# We'll also import a few standard python libraries
from matplotlib import pyplot
import numpy as np
import time# These are the droids you are looking for.
from caffe2.python import core, workspace
from caffe2.proto import caffe2_pb2

如果你看到一些警告:Caffe2不支持GPU。这说明,你正在跑的Caffe2仅仅编译了CPU模式。不用担心,Caffe2在CPU上也是可以运行的。

Workspaces

让我们先来介绍Workspace,它包含了所有数据。如果你熟悉Matlabworksapce包含了所有你创建的blob并保存在内存中。现在,让我们考虑一个N维的blob,blob和numpy的矩阵很像,但是它是连续的。接下来,我们将展示blob实际上是一种能指向任何C++类型对象的指针。下面,我们来看看接口是什么样的的。

Blobs()函数可以打印workspace里面所有的blobs。HasBlob则用于查询worksapce里面是否存在某个blob。不过,目前为止,我们的workspace里面没有任何东西。

print("Current blobs in the workspace: {}".format(workspace.Blobs()))
print("Workspace has blob 'X'? {}".format(workspace.HasBlob("X")))

FeedBlob()函数用于向worksapce里面传递blob。

X = np.random.randn(2, 3).astype(np.float32)
print("Generated X from numpy:\n{}".format(X))
workspace.FeedBlob("X", X)

打印出来的X如下:

Generated X from numpy:
[[-0.56927377 -1.28052795 -0.95808828][-0.44225693 -0.0620895  -0.50509363]]

让我们看一下workspace里面的blob是什么样的。

print("Current blobs in the workspace: {}".format(workspace.Blobs()))
print("Workspace has blob 'X'? {}".format(workspace.HasBlob("X")))
print("Fetched X:\n{}".format(workspace.FetchBlob("X")))

输出如下:

Current blobs in the workspace: [u'X']
Workspace has blob 'X'? True
Fetched X:
[[-0.56927377 -1.28052795 -0.95808828][-0.44225693 -0.0620895  -0.50509363]]

接着验证两个矩阵是否相等:

np.testing.assert_array_equal(X, workspace.FetchBlob("X"))

注意,如果你访问一个不存在的blob,将会引发一个错误:

try:workspace.FetchBlob("invincible_pink_unicorn")
except RuntimeError as err:print(err)

错误输出如下:

[enforce fail at pybind_state.cc:441] gWorkspace->HasBlob(name).

另外,有一个你目前可能还用不上的东西:你可以定义两个不同名字的workspace,并且在他们之间切换。不同workspace的bolb是相互分离的。你可以通过CurrentWorkspace()函数来访问当前的workspace。下面演示了如何切换不同的workspace和创建新的workspace。

print("Current workspace: {}".format(workspace.CurrentWorkspace()))
print("Current blobs in the workspace: {}".format(workspace.Blobs()))# 切换到`gutentag` workspace,第二个参数`True`表示,如果`gutentag`不存在,则创建一个。
workspace.SwitchWorkspace("gutentag", True)# 现在重新打印,注意到当前的workspace是`gutentag`,并且其中不包含任何东西。
print("Current workspace: {}".format(workspace.CurrentWorkspace()))
print("Current blobs in the workspace: {}".format(workspace.Blobs()))

程序输出:

Current workspace: default
Current blobs in the workspace: ['X']
Current workspace: gutentag
Current blobs in the workspace: []

重新切换回到defaultworkspace

workspace.SwitchWorkspace("default")
print("Current workspace: {}".format(workspace.CurrentWorkspace()))
print("Current blobs in the workspace: {}".format(workspace.Blobs()))

并有如下输出:

Current workspace: default
Current blobs in the workspace: ['X']

最后,调用ResetWorkspace()函数可以清空当前的workspace的所有东西

workspace.ResetWorkspace()

Operators

Caffe2中,operator就像函数一样。从C++的角度理解,operator全部从一个通用的接口继承而来,它们通过类型进行注册,所以,我们可以在运行时调用不同的操作。operator的接口定义在caffe2/proto/caffe2.proto文件中。Operator根据输出产生相应的输出。
记住,在Caffe2的Python接口中,当我们说“创建一个operator”时,程序并没有跑起来,它只是创建了关于这个operator的protocol buffere,也就是定义了这个operator,但还没执行。之后,这个operator才会传递给C++接口禁止执行。如果你不明白什么是protobuf,那么你可以看下这个链接.
1.
下面看一个实际例子:

# Create an operator.
op = core.CreateOperator("Relu", # The type of operator that we want to run["X"], # 输入 blobs 的名字的列表["Y"], # A list of 输出 blobs by their names
)
# and we are done!

我们之前说到,创建op(operator),事实上只是创建了一个protobuf对象。我们可以查看它的内容。

print("Type of the created op is: {}".format(type(op)))
print("Content:\n")
print(str(op))

输出如下:

Type of the created op is: <class 'caffe2.proto.caffe2_pb2.OperatorDef'>
Content:
input: "X"
output: "Y"
name: ""
type: "Relu"

现在跑起这个operator,我们首先需要向workspace中传入数据X,然后简单的调用workspace.RunOperatorOnce(operator)函数就可以。

workspace.FeedBlob("X", np.random.randn(2, 3).astype(np.float32))
workspace.RunOperatorOnce(op)

执行完后,让我们检查下这个operator是否正确操作。在这个操作中我们使用的是Relu函数。Relu函数在输入小于0时,取0,在输入大于0时,保持不变。

print("Current blobs in the workspace: {}\n".format(workspace.Blobs()))
print("X:\n{}\n".format(workspace.FetchBlob("X")))
print("Y:\n{}\n".format(workspace.FetchBlob("Y")))
print("Expected:\n{}\n".format(np.maximum(workspace.FetchBlob("X"), 0)))

输出如下,可以看到输出Y和你期望值一样,这个operator正确跑起来了:

Current blobs in the workspace: ['X', 'Y']
X:
[[ 1.03125858  1.0038228   0.0066975 ][ 1.33142471  1.80271244 -0.54222912]]
Y:
[[ 1.03125858  1.0038228   0.0066975 ][ 1.33142471  1.80271244  0.        ]]Expected:
[[ 1.03125858  1.0038228   0.0066975 ][ 1.33142471  1.80271244  0.        ]]

2.
当然Operator也支持选项参数。选项参数通过key-value对确定。下面是一个简单的例子:创建一个tensor并且用高斯随机值填充它。

op = core.CreateOperator("GaussianFill",[], # GaussianFill does not need any parameters.["Z"],shape=[100, 100], # shape argument as a list of ints.mean=1.0,  # mean as a single floatstd=1.0, # std as a single float
)
print("Content of op:\n")
print(str(op))

看看输出:

Content of op:
output: "Z"
name: ""
type: "GaussianFill"
arg {name: "std"f: 1.0
}
arg {name: "shape"ints: 100ints: 100
}
arg {name: "mean"f: 1.0
}

然后我们跑起这个op,看看事情是否如期。

workspace.RunOperatorOnce(op)
temp = workspace.FetchBlob("Z")
pyplot.hist(temp.flatten(), bins=50)
pyplot.title("Distribution of Z")

image.png
没错,就是这样。

Nets

Net其实是多个operator的集合,就像写程序时一行一行的命令。

让我们创建一个等价于下面Python代码的网络。

X = np.random.randn(2, 3)
W = np.random.randn(5, 3)
b = np.ones(5)
Y = X * W^T + b

Caffe2中的core.net是对NetDef protocol buffer的一个封装类。当创建一个网络时,这个对象完全是空的,除了拥有它的名字信息外。

net = core.Net("my_first_net")
print("Current network proto:\n\n{}".format(net.Proto()))
Current network proto:
name: "my_first_net"

接着创建一个blob,命名为“X”,使用高斯函数进行填充。

X = net.GaussianFill([], ["X"], mean=0.0, std=1.0, shape=[2, 3], run_once=0)
print("New network proto:\n\n{}".format(net.Proto()))

这时网络的结构如下

New network proto:
name: "my_first_net"
op {output: "X"name: ""type: "GaussianFill"arg {name: "std"f: 1.0}arg {name: "run_once"i: 0}arg {name: "shape"ints: 2ints: 3}arg {name: "mean"f: 0.0}
}

聪明的读者肯定想起了我们之前提到的core.CreateOperator()。事实上,当我们有了一个net,我们可以直接创建一个operator然后通过Python接口加到net中去。比如,你调用了net.SomeOp,这里的SomeOp是一个注册了的operator的字符串,因此上面的操作和下面等效。

op = core.CreateOperator("SomeOp", ...)
net.Proto().op.append(op)

译者注:
比如在我用op = core.CreateOperator("GaussianFill",[], ["Z"],shape=[100, 100],mean=1.0, std=1.0)创建了一个op,op的type为“GaussianFill”,这是一个注册了的类型。然后再调用net.Proto().op.append(op)把这个op添加到网络中去。
以上的操作可以同过net来调用直接实现。直接使用op的type string---“GaussianFill”作为函数名字,net.GaussianFill([], ["X"], mean=0.0, std=1.0, shape=[2, 3], run_once=0)。

当然,读者可能感到困惑,X是什么?X是一个 BlobReference,这个引用包含两样东西:
- 名字,可以通过str(X)来访问得到
- 它是哪个net创建的,记录在其中的变量_from_net
现在让我们验证它。同样记住,我们还没有跑任何东西,所以X只是个符号,里面什么也没有。别只望它会输出什么值。

print("Type of X is: {}".format(type(X)))
print("The blob name is: {}".format(str(X)))
Type of X is: <class 'caffe2.python.core.BlobReference'>
The blob name is: X

让我们继续创建W和b.

W = net.GaussianFill([], ["W"], mean=0.0, std=1.0, shape=[5, 3], run_once=0)
b = net.ConstantFill([], ["b"], shape=[5,], value=1.0, run_once=0)

现在一个简单的代码:Note由于BlonReference对象知道它由什么网络创建的,所以除了从net中创建op,你还可以通过BlobReference创建op。因此,我们可以通过如下方式创建FC操作。

Y = X.FC([W, b], ["Y"])

事实上,在底下,X.FC(...)只是简单的委托net.FC来实现,X.FC()会将X作为op的第一个输入。所以上面的操作其实等价于下面的:

Y = net.FC([X, W, b], ["Y"])

现在让我们看下当前这个网络。

print("Current network proto:\n\n{}".format(net.Proto()))
Current network proto:
name: "my_first_net"
op {output: "X"name: ""type: "GaussianFill"arg {name: "std"f: 1.0}arg {name: "run_once"i: 0}arg {name: "shape"ints: 2ints: 3}arg {name: "mean"f: 0.0}
}
op {output: "W"name: ""type: "GaussianFill"arg {name: "std"f: 1.0}arg {name: "run_once"i: 0}arg {name: "shape"ints: 5ints: 3}arg {name: "mean"f: 0.0}
}
op {output: "b"name: ""type: "ConstantFill"arg {name: "run_once"i: 0}arg {name: "shape"ints: 5}arg {name: "value"f: 1.0}
}
op {input: "X"input: "W"input: "b"output: "Y"name: ""type: "FC"
}

是不是觉得太过冗长?GOOD~让我们尝试下把它变成一个图。用ipython显示。

from caffe2.python import net_drawer
from IPython import display
graph = net_drawer.GetPydotGraph(net, rankdir="LR")
display.Image(graph.create_png(), width=800)

image.png
目前为止,我们已经定义了一个Net,但是并没有执行任何东西。记住,上面的net只是一个protobuf,仅仅定义了网路的结构。当我们真正跑起这个网络时,底层发生的事件如下。
- 实例化protobuf中定义的C++net 对象
- 调用实例化后的net的Run()函数
在我们进行任何操作前,我们应该先使用ResetWorkspace()清空workspace里的东
西。
NOTE有两种方式通过python来跑一个网络。我们选择第一种来展示。

  1. 使用 workspace.RunNetOnce()
  2. 第二种更复杂点:需要两步,a) 调用workspace.CreateNet()创建C++net对象,b)使用workspace.RunNet(),这步需要传递网络的名字作为参数。

第一种

workspace.ResetWorkspace()
print("Current blobs in the workspace: {}".format(workspace.Blobs()))
workspace.RunNetOnce(net)
print("Blobs in the workspace after execution: {}".format(workspace.Blobs()))
# Let's dump the contents of the blobs
for name in workspace.Blobs():print("{}:\n{}".format(name, workspace.FetchBlob(name)))

输出如下:

Current blobs in the workspace: []
Blobs in the workspace after execution: ['W', 'X', 'Y', 'b']
W:
[[-0.96537346  0.42591459  0.66788739][-0.47695673  2.25724339 -0.10370601][-0.20327474 -3.07469416  0.47715324][-1.62159526  0.73711687 -1.42365313][ 0.60718107 -0.50448036 -1.17132831]]
X:
[[-0.99601173 -0.61438894  0.10042733][ 0.23359862  0.15135486  0.77555442]]
Y:
[[ 1.76692021  0.07781416  3.13944149  2.01927781  0.58755434][ 1.35693741  1.14979863  0.85720366 -0.37135673  0.15705228]]
b:
[ 1.  1.  1.  1.  1.]

第二种
现在尝试第二种方法去创建这个网络,并跑起它。

workspace.ResetWorkspace()
print("Current blobs in the workspace: {}".format(workspace.Blobs()))
workspace.CreateNet(net)
workspace.RunNet(net.Proto().name)#传入名字
print("Blobs in the workspace after execution: {}".format(workspace.Blobs()))
for name in workspace.Blobs():print("{}:\n{}".format(name, workspace.FetchBlob(name)))

输出

Current blobs in the workspace: []
Blobs in the workspace after execution: ['W', 'X', 'Y', 'b']
W:
[[-0.29295802  0.02897477 -1.25667715][-1.82299471  0.92877913  0.33613944][-0.64382178 -0.68545657 -0.44015241][ 1.10232282  1.38060772 -2.29121733][-0.55766547  1.97437167  0.39324901]]
X:
[[-0.47522315 -0.40166432  0.7179445 ][-0.8363331  -0.82451206  1.54286408]]
Y:
[[ 0.22535783  1.73460138  1.2652775  -1.72335696  0.7543118 ][-0.71776152  2.27745867  1.42452145 -4.59527397  0.4452306 ]]
b:
[ 1.  1.  1.  1.  1.]

RunNetOnce()RunNet()之间有不少差异,其中最大的差异就是计算耗时。因为RunNetOnce()涉及到protobuf的序列化,和实例化网络。这可能会使用很长时间。让我们来看下开销。

# It seems that %timeit magic does not work well with
# C++ extensions so we'll basically do for loops
start = time.time()
for i in range(1000):workspace.RunNetOnce(net)
end = time.time()
print('Run time per RunNetOnce: {}'.format((end - start) / 1000))start = time.time()
for i in range(1000):workspace.RunNet(net.Proto().name)
end = time.time()
print('Run time per RunNet: {}'.format((end - start) / 1000))

输出如下:

Run time per RunNetOnce: 0.000364284992218
Run time per RunNet: 4.42600250244e-06

可以看到RunNet()更快。

结语:以上就是Caffe2的Python接口的一些主要部件。装载请注明出处:
http://www.jianshu.com/c/cf07b31bb5f2

转载于:https://www.cnblogs.com/sysuzyq/p/6824916.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 开发者最应该知道的命令汇总

&#xff11;最近发现一个好东西&#xff0c;在 github 上发现的&#xff0c;我觉得非常适合大家研究 linux&#xff0c;说白了就是一些命令而已&#xff0c;只不过是作者帮忙总结好了&#xff0c;比较适合大家开发和学习 linux 系统&#xff0c;so , 推荐给大家学习下。https:…

华为任职资格_华为采购总部专业任职资格标准|

目 录 序 言 概述 .........................第一部分 级别定义.....................第二部分 资格标准 ....................1、采购工程师&#xff08;生产采购&#xff09;任职资格标准........2、采购员&#xff08;生产采购&#xff09;任职资格标准............3、采购员…

C 语言内存分配

&#xff11;昨天有一个群里的同学问我&#xff0c;他问我的问题是 c 语言函数是存在哪里的&#xff1f;是如何执行的&#xff1f;我下意识的觉得这位同学应该是个初学者&#xff0c;所以今天就写下一些基础方面的内容&#xff0c;「C语言的内存布局」。程序代码可以看做是一个…

没有梦想,你跟咸鱼有什么分别?

&#xff11;标题起的有点夸张&#xff0c;其实这个就是一个招聘贴&#xff0c;之前从来没有用发头条文章来招聘&#xff0c;实在不好意思&#xff0c;这个招聘对我非常重要&#xff0c;这是一个非常好的朋友公司的招聘信息&#xff0c;也希望大家帮忙扩散一下&#xff0c;因为…

一个很Low的通讯录管理系统(但是能用)C/C++单链表实现

通讯录管理系统的设计 问题需求分析 在计算机还未普及之前通讯管理都是由联系人采用名片&#xff0c;通讯录往往采用的是笔录手工记帐的方式来操作的。现在一般的通讯录管理都是采用计算机作为工具的实用的计算机通讯录管理程序来帮助人们进行更有效的通讯录信息管理。本通讯…

2017《面向对象程序设计》课程作业三

作业链接github链接 对于文件读写和多参数主函数学习过程中遇到的问题 这次文件读写改用了C的形式&#xff0c;然后总体还算顺利&#xff0c;借鉴了林燊的&#xff0c;因为他写的代码最容易看懂&#xff1b;还有就是借鉴了《C程序设计》&#xff0c;讲真&#xff0c;谭浩强的还…

华为不做黑寡妇,开源编译器,与友商共建安卓性能

&#xff11;今天我的一个老哥开了头条号&#xff0c;第一次发文章&#xff0c;我觉得不错&#xff0c;拿来用用&#xff0c;给大家看看华为技术总工的文采。这位总工潜伏在我的微信群里很少说话&#xff0c;大家一定要有这个想法&#xff0c;就是最低调的那个人&#xff0c;真…

点击链接如何直接跳转到相对应的聊天窗口

解决这个问题的步骤如下&#xff1a; <a target"_blank" href"http://wpa.qq.com/msgrd?v3&uin3237465337&siteqq&menuyes">一、登陆腾讯官方网站&#xff1a;http://wp.qq.com/ 二、登陆之后&#xff0c;点“设置”&#xff0c;按下图…

哈夫曼树编码与译码(完整C/C++实现代码)

哈夫曼编码的设计与应用 问题需求分析 用哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式&#xff0c;哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法&#xff0c;该方法完全依据字符出现概率来构造异字头的平均长…

移动应用开发实例_物联网改变移动应用开发的4种方式

图片来源&#xff1a;pixabay.com来源&#xff1a;物联之家网(iothome.com)转载请注明来源&#xff01;物联网改变了移动应用程序的开发格局。那么&#xff0c;为物联网开发移动应用程序有何不同&#xff1f;物联网与移动应用程序开发齐头并进。物联网改变了人类与机器的互动方…

谁都能看懂的网络模型知识

&#xff11;.网络是我们做嵌入式 避无可避的知识点&#xff0c;但是网络的层次很多&#xff0c;很多时候我们根本理解不了其中的层次和作用&#xff0c;今天跟我们公司的 X 总聊到这个&#xff0c;给我普及了一些知识&#xff0c;我觉得非常有用&#xff0c;分享给大家。最近事…

常用排序算法以及算法性能测试(完整C/C++代码实现)

排序算法性能的比较 注: 由于只是测试算法性能, 所以不会对排序算法做深入讲解, 在随后的时间将会推出排序的详细讲解 问题需求分析 排序算法经过了很长时间的演变&#xff0c;产生了很多种不同的方法。每种算法主要针对不同的数列进行排序&#xff0c;这些排序算法具有各自…

我就随便BB一下

&#xff11;.如果我开始写文章的时候&#xff0c;停顿了几分钟&#xff0c;那结果应该很明显&#xff0c;这一定是一篇比较垃圾的文章&#xff0c;没什么东西值得看&#xff0c;所以我把之前的删除了&#xff0c;重新开头来写&#xff0c;我认为&#xff0c;一个好的开头一定是…

和我一起探索嵌入式

&#xff11;.本文为微信群管理员小磊投稿作品&#xff0c;作者计划编写一系列文章&#xff0c;该篇为第一篇&#xff0c;如果有做STM32的同学这将是一个非常好的系列教程&#xff0c;欢迎关注。我15年刚建立了一个BLE的QQ群&#xff0c;很有幸认识了小磊同学&#xff0c;一个非…

Java NIO_I/O基本概念_Java中的缓冲区(Buffer)_通道(Channel)_网络I/O

I/O基本概念 缓冲区基础 缓冲区是I/O的基础, 进程使用read(), write()将数据读出/写入从缓冲区中; 当缓冲区写满, 内核向磁盘发出指令, 将缓冲区中数据写入磁盘中(这一步不需要CPU), 当磁盘控制器将缓冲区装满, 内核将缓冲区数据拷贝到进程中指定的缓冲区; 操作如下图: 当中…

跟一个大佬前辈交流了一下

&#xff11;.最近&#xff0c;跟我们公司的测试总监聊天&#xff0c;我随便问了下他几个问题&#xff0c;他也给出了答案&#xff0c;在这里随便聊下&#xff0c;希望给大家的职业生涯中有一些借鉴的作用。也能给新入职场的同学一些方向和指引。2.先介绍下这个技术总监&#x…

LINQ简记(1):基本语法

关于LINQ&#xff08;语言集成查询&#xff09;是.NET 3.5和Visual Studio 2008以上版本中引入的一种有趣的全新概念&#xff0c;语言版本有VB和C#&#xff0c;由于C#与.NET平台结合最为紧密&#xff0c;也是MS当初首推的语言&#xff0c;因此&#xff0c;本系列文章的示例代码…

我认识的一位前辈~

&#xff11;.我最近认识了一个老前辈&#xff0c;关注了我的公众号加了我的好友认识的&#xff0c;我想介绍一下这位前辈&#xff0c;不是因为他有多成功&#xff0c;也不是因为他给了我很多钱&#xff0c;我觉得他是一个在平常不过的人了&#xff0c;因为太过于平凡的思考方式…

机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现

下面的有些叙述基于我个人理解, 可能与专业书籍描述不同, 但是最终都是表达同一个意思, 如果有不同意见的小伙伴, 请在评论区留言, 我不胜感激. 参考: 周志华-机器学习 https://blog.csdn.net/xiaohukun/article/details/78112917 https://blog.csdn.net/fuqiuai/article/d…

http数据绑定spring mvc详解

转载于:https://www.cnblogs.com/panxuejun/p/6834365.html