本文参考自: 原文地址
Caffe2 涉及的概念
1. Blobs,Workspace,Tensors
Caffe2 的 Data 是以 blobs 的形式组织的.
blob 即是内存中被命名的 data chunk(数据块).
blobs 一般包含一个 tensor(可以看做是多维数组),在 Python 中的存在形式是 numpy arrays.
Workspace 存储所有的 blobs. 如下例,展示了将 blobs 送入 workspace (Feed) 以及从 workspace 读取 blobs [Fetch]的方法.
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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
2 Nets,Operators
Caffe2 基础的模型抽象是 net.
net 是由 operators 组成的 graph,每一个 operator 根据输入 input blobs 集,而输出一个或多个 output blobs.
以构建简单网络模型为例,其包括以下几种组成:
1 个全连接层(FC);
1 个采用 softmax 的 Sigmoid 激活层;
1 个 CrossEntropy 层
这里不直接构建 nets,而是借助 model_helpers 来进行 nets 构建; model_helpers 是创建 nets 的 Python 类.
将待创建的网络记为 “my first net”,ModelHelper 会另外创建两个相互关联的 nets:
- 一个是,参数初始化网络(记 init_net)
- 一个是,真实训练网络(记 exec_net)
首先,随机生成 data 和label,并作为 blobs 输入到 workspace:
# 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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
然后,采用 model_helper 来创建 init_net 和 exec_net;并接着对 model 采用 FC operator 添加全连接层. 这里 FC op 需要先生成一些随机 fills.
生成随机 fills 后,即可将 fc ops 添加到模型,并使用创建的 weights 和 bias blobs,可以根据其名字进行调用.
Caffe2 中,FC op 包括三部分: input blob,weights 和 bias. Weights 和 bias 可以使用 XavierFill 或 ConstantFill初始化,参数包括三部分: [ ] - 空数组;’fc_w/fc_b’ - 名称;shape - shape=[output, input].
# Create model using a model helper
m = model_helper.ModelHelper(name="my first net")
# Create random fills
weight = m.param_init_net.XavierFill([], 'fc_w', shape=[10, 100])
bias = m.param_init_net.ConstantFill([], 'fc_b', shape=[10, ])
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"])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
回顾下创建过程:
首先,创建内存里的 input data 和 label blobs;实际应用中,从相应的 database 来加载读取.
data 和 label blobs 的 first dim=16,即 batchsize=16.
基于 ModelHelper 可以进行处理许多 Caffe2 operators,更多细节参考 ModelHelper’s Operator List.
然后,通过定义多个 operators 来创建模型:FC, Sigmoid 和 SoftmaxWithLoss.
此时,只是定义了 operators 和 model.
ModelHelper 创建了两个 nets:
- m.param_init_net
只运行一次;初始化参数 blobs;
- m.net
训练网络.
网络定义保存为 protobuf 结构,可以通过调用 net.Proto() 来查看网络结构.
print(m.net.Proto())
- 1
输出如下:
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"
}
external_input: "data"
external_input: "fc_w"
external_input: "fc_b"
external_input: "label"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
参数初始化化网络:
print(m.param_init_net.Proto())
- 1
Caffe2 API 的基本思想:
采用 Python 方便快捷的组织网络来训练模型;
将网络以序列化 serialized protobuffers 传递到 C++ code;
然后,利用 C++ code 运行网络.
3. Executing
定义好模型训练 operators 后,可以开始训练模型.
首先,运行一次参数初始化网络:
workspace.RunNetOnce(m.param_init_net)
- 1
然后,创建训练网络:
workspace.CreateNet(m.net)
- 1
接着,网络训练:
# 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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
查看 output blobs 中存储的结果(tensor 或 numpy arrays):
print(workspace.FetchBlob("softmax"))
print(workspace.FetchBlob("loss"))
- 1
- 2
4. Backward pass
以上网络训练只有 forward pass,没有学习.
通过对 forward pass 中的每个 operator 创建其梯度 operators,即可 backward pass.
如果已经根据规范进行尝试,可以采用以下处理来检查结果.
调用 RunNetOnce 前,插入:
m.AddGradientOperators([loss])
- 1
检查 protobuf 输出:
print(m.net.Proto())
- 1
更多 Caffe2 材料,可以参考:Caffe2 Tutorials Overview.
5. Reference
[1] - Caffe2 Intro Tutorial