caffe2(四):Nets

Nets
nets本质上是计算图。为了保持前后一致性保留名称Net(同时也向神经网络致敬)。网络由多个operators组成,类似于一段程序由一系列命令组成。
当我们讨论nets时候,我们通常也讨论BlobReference,它是一个对象,包装了一个字符串,所以我们可以做简单的运算符链接操作。
创建一个基本上等同于下面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基本上为空,创建网络并展示proto内容。

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

name: "my_first_net"

Let’s create a blob called X, and use GaussianFill to fill it with some random data.

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: 2
    ints: 3
  }
  arg {
    name: "mean"
    f: 0.0
  }
}

你可能已经观察到这和之前的core.CreateOperator调用有一些不同。基本上,当我们有一个网络,你可以直接创建一个运算符并将它添加到网络里。本质上,如果你调用net.SomeOp,SomeOp是一个注册的运算符类型的字符串,可以翻译成:

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

你可能会想X是什么,X是一个BlobReference,它基本上记录了两件事情:

  • 通过str(X)查看X的名字

  • _from_net记录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)

由于BlobReference对象知道从哪个网络生成,除了从网络创建运算符之外,还可以从BlobReferences创建运算符,我们以这种方式创建FC运算符。

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

等价于

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: 2
    ints: 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: 5
    ints: 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"
}

太冗长了吗? 我们尝试将其可视化为图形。 Caffe2为此提供了极小的图形可视化工具。

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

假装有图….

我们定义一个Net,但是没有任何执行。上面的网络本质上就是一个保留网络定义的protobuf。实际运行网络时,发生了下面的情况:

  • 从protobuf实例化一个C++网络对象;
  • 调用实例网络的Run()函数。

在做任何操作之前,我们应该调用ResetWorkspace()先把工作区变量清除掉。
使用python有两种方式运行网络,我们会用第一种方式来展示例子:
1. Call workspace.RunNetOnce(), which instantiates, runs and immediately destructs the network
2. Call workspace.CreateNet() to create the C++ net object owned by the workspace, then call workspace.RunNet(), passing the name of the network to it

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.]

现在,我们用第二种方式来创建网络并运行它。
首先,还是先要 clear the variables with ResetWorkspace()
然后,用workspace的netobject 来创建网络CreateNet(net_object)
最后,运行网络RunNet(net_name)

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: [u'W', u'X', u'Y', u'b']
W:
[[-0.49780178  0.0896128  -1.1650279 ]
 [-1.9277409   0.91667885  1.2152035 ]
 [-0.80195075 -0.17179072  0.8195034 ]
 [ 0.21857451 -0.9942886   0.9358572 ]
 [-0.7295994  -1.085294    1.1550978 ]]
X:
[[-0.94531673  0.2626604  -1.3781935 ]
 [-0.15628844  1.2679638   0.40703335]]
Y:
[[ 3.099752    1.3883154   0.58354056 -0.7575747  -0.18730962]
 [ 0.71722126  2.9582276   1.2410765   0.0860424   0.20807779]]
b:
[1. 1. 1. 1. 1.]

RunNetOnce和RunNet之间有一些区别,但主要区别在于计算时间开销。 由于RunNetOnce涉及到将protobuf序列化以在Python和C之间传递并实例化网络,所以运行可能需要更长时间。 在这种情况下,我们看看什么是开销:

# 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()
workspace.CreateNet(net)
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值