caffe2 概念
您可以在下面了解有关Caffe2的主要概念的更多信息,这些概念对于理解和开发Caffe2模型至关重要。
Blobs和Workspace,Tensors
数据在caffe2中组成成为blobs, blobs是内存中的一个命名的块. 大部分的blobs包含一个tensor(可以想成多维向量),在python中转换成为numpy数组.
Workspace保存所有的blobs. 下面的例子显示如何填入blobs到workspace并再次取出它.Workspaces会在你使用它时进行初始化
from caffe2.python import workspace, model_helper
import numpy as np
# Create random tensor of three dimensions
x = np.random.rand(4, 3, 2)
print(x)
print(x.shape)
workspace.FeedBlob("my_x", x)
x2 = workspace.FetchBlob("my_x")
print(x2)
Nets 和 Operators
Caffe2中的基本模型抽象是一个网络(network的缩写)。 网络是运算符的图,每个运算符采用一组输入Blob并产生一个或多个输出Blob。
在下面的代码块中,我们将创建一个超级简单的模型。 它将具有以下组件:
- 一个全链接层(FC)
- 一个Sigmoid激活函数包含Softmax
- 一个交叉熵损失函数
直接构成一个nets非常繁琐,因此最好使用模型帮助程序(python类用于创建nets). 即使我们叫他"my first net",ModelHelper将会创建两个关联的网络:
- 一个初始化参数(参考init_net)
- 一个运行实际训练(参考 exec_net)
# Create the input data
data = np.random.rand(16, 100).astype(np.float32)
# Create labels for the data as integers [0, 9].
label = (np.random.rand(16) * 10).astype(np.int32)
workspace.FeedBlob("data", data)
workspace.FeedBlob("label", label)
创建随机的data和label,提供给workspace的blobs
# Create model using a model helper
m = model_helper.ModelHelper(name="my first net")
我们使用model_helper来创建刚才提到的两个网络(init_net和exec_net).我们计划使用FC operator添加一个全连接层,但首先我们需要做准备工作,创建随机填充blobs以提供给FC需要的weight和bias.添加FC操作时我们通过名称引用weight和bias.
weight = m.param_init_net.XavierFill([], 'fc_w', shape=[10, 100])
bias = m.param_init_net.ConstantFill([], 'fc_b', shape=[10, ])
在Caffe2中FC操作接受输入blob(我们的数据)weights和bias.weights和bias使用XavierFill和ConstantFill(将一个空的数组,名称,和shape填充)
fc_1 = m.net.FC(["data", "fc_w", "fc_b"], "fc1")
pred = m.net.Sigmoid(fc_1, "pred")
softmax, loss = m.net.SoftmaxWithLoss([pred, "label"], ["softmax", "loss"])
查看上面的代码:
首先,我们在内存中创建了输入数据和标签Blob(实际上,您将从诸如数据库之类的输入数据源加载数据)。 请注意,数据和标签Blob的第一维为“ 16”; 这是因为模型的输入是一次最少16个样本的小批量。 可以通过ModelHelper直接访问许多Caffe2运算符,并且可以一次处理一小部分输入。
其次,我们通过定义一堆运算符来创建模型:FC,Sigmoid和SoftmaxWithLoss。 注意:此时,运算符尚未执行,您只是在创建模型的定义(也就是定义模型结构)。
Model helper将会创建两个网络:m.param_init_net此net只运行一次.它将所有的参数blobs如FC层的weights进行初始化.实际训练使用的是m.net.这些自动发生对使用者来说透明的.
这个网络定义存储在protobuf结构中,可视使用net.Proto()检查他:
您可以看到如何有两个运算符为FC运算符的权重和偏差斑点创建随机填充。
这是Caffe2 API的主要思想:使用Python方便地组成网络来训练模型,将这些网络作为序列化的原型缓冲区传递给C ++代码,然后让C ++代码以最佳性能运行网络。
执行
现在,当我们定义了模型训练操作员后,就可以开始运行它来训练模型。
首先,我们只运行一次参数初始化:
创建实际训练网络
我们创建其一次然后有效的多次运行它:
# Run 100 x 10 iterations
for _ in range(100):
data = np.random.rand(16, 100).astype(np.float32)
label = (np.random.rand(16) * 10).astype(np.int32)
workspace.FeedBlob("data", data)
workspace.FeedBlob("label", label)
workspace.RunNet(m.name, 10) # run for 10 times
注意我们如何只将m.name而不是net定义本身传递给RunNet()。 由于网络是在工作空间内创建的,因此我们无需再次传递定义。
执行后我们抗获取存储在输出blobs的结果
print(workspace.FetchBlob("softmax"))
print(workspace.FetchBlob("loss"))
反向传播
This net only contains the forward pass, thus it is not learning anything. The backward pass is created by adding the gradient operators for each operator in the forward pass.
If you want to try this, add the following steps and examine the results!
Insert before you call RunNetOnce():
m.AddGradientOperators([loss])
Examine the protobuf output:
print(m.net.Proto())
name: "my first net"
op {
input: "data"
input: "fc_w"
input: "fc_b"
output: "fc1"
name: ""
type: "FC"
}
op {
input: "fc1"
output: "pred"
name: ""
type: "Sigmoid"
}
op {
input: "pred"
input: "label"
output: "softmax"
output: "loss"
name: ""
type: "SoftmaxWithLoss"
}
#从这一行之后就是方向梯度传播了
op {
input: "loss"
output: "loss_autogen_grad"
name: ""
type: "ConstantFill"
arg {
name: "value"
f: 1.0
}
}
op {
input: "pred"
input: "label"
input: "softmax"
input: "loss_autogen_grad"
output: "pred_grad"
name: ""
type: "SoftmaxWithLossGradient"
is_gradient_op: true
}
op {
input: "pred"
input: "pred_grad"
output: "fc1_grad"
name: ""
type: "SigmoidGradient"
is_gradient_op: true
}
op {
input: "data"
input: "fc_w"
input: "fc1_grad"
output: "fc_w_grad"
output: "fc_b_grad"
output: "data_grad"
name: ""
type: "FCGradient"
is_gradient_op: true
}
external_input: "data"
external_input: "fc_w"
external_input: "fc_b"
external_input: "label"