Caffe2 - 创建您自己的网络
在本课中,您将学习在 Caffe2 中定义单层神经网络 (NN)并在随机生成的数据集上运行它。我们将编写代码以图形方式描述网络架构,打印输入、输出、权重和偏差值。要理解本课,您必须熟悉神经网络架构、其术语以及其中使用的数学。
网络架构
假设我们想要构建一个单层 NN,如下图所示 −
从数学上讲,该网络由以下 Python 代码表示 −
Y = X * W^T + b
其中 X、W、b 是张量,Y 是输出。我们将用一些随机数据填充所有三个张量,运行网络并检查 Y 输出。为了定义网络和张量,Caffe2 提供了几个 Operator 函数。
Caffe2 运算符
在 Caffe2 中,Operator 是计算的基本单位。Caffe2 Operator 表示如下。
Caffe2 提供了详尽的运算符列表。对于我们目前正在设计的网络,我们将使用名为 FC 的运算符,它计算将输入向量 X 传递到具有二维权重矩阵 W 和一维偏差向量 b 的完全连接网络的结果。换句话说,它计算以下数学方程式
Y = X * W^T + b
其中 X 的维度为 (M x k),W 的维度为 (n x k),而 b 为 (1 x n)。输出 Y 的维度为 (M x n),其中 M 是批量大小。
对于向量 X 和 W,我们将使用 GaussianFill 运算符来创建一些随机数据。为了生成偏差值b,我们将使用ConstantFill运算符。
现在我们将继续定义我们的网络。
创建网络
首先,导入所需的包 −
from caffe2.python import core, workingspace
接下来,通过调用core.Net定义网络,如下所示 −
net = core.Net("SingleLayerFC")
网络的名称指定为SingleLayerFC。此时,创建名为 net 的网络对象。到目前为止,它不包含任何层。
创建张量
现在我们将创建网络所需的三个向量。首先,我们将通过调用 GaussianFill 运算符创建 X 张量,如下所示 −
X = net.GaussianFill([], ["X"], mean=0.0, std=1.0, shape=[2, 3], run_once=0)
X 向量的维度为 2 x 3,平均数据值为 0,0,标准差为 1.0。
同样,我们创建 W 张量,如下所示 −
W = net.GaussianFill([], ["W"], mean=0.0, std=1.0, shape=[5, 3], run_once=0)
W 向量的大小为 5 x 3。
最后,我们创建大小为 5 的偏差 b 矩阵。
b = net.ConstantFill([], ["b"], shape=[5,], value=1.0, run_once=0)
现在,到了代码中最重要的部分,即定义网络本身。
定义网络
我们在以下 Python 语句 − 中定义网络
Y = X.FC([W, b], ["Y"])
我们在输入数据 X 上调用 FC 运算符。权重在 W 中指定,偏差在 b 中指定。输出为 Y。或者,您可以使用以下 Python 语句创建网络,该语句更详细。
Y = net.FC([X, W, b], ["Y"])
此时,网络只是创建。在我们至少运行一次网络之前,它不会包含任何数据。在运行网络之前,我们将检查其架构。
打印网络架构
Caffe2 在 JSON 文件中定义网络架构,可以通过在创建的 net 对象上调用 Proto 方法来检查它。
print (net.Proto())
这将产生以下输出 −
name: "SingleLayerFC" op { output: "X" name: "" type: "GaussianFill" arg { name: "mean" f: 0.0 } arg { name: "std" f: 1.0 } arg { name: "shape" ints: 2 ints: 3 } arg { name: "run_once" i: 0 } } op { output: "W" name: "" type: "GaussianFill" arg { name: "mean" f: 0.0 } arg { name: "std" f: 1.0 } arg { name: "shape" ints: 5 ints: 3 } arg { name: "run_once" i: 0 } } op { output: "b" name: "" type: "ConstantFill" arg { name: "shape" ints: 5 } arg { name: "value" f: 1.0 } arg { name: "run_once" i: 0 } } op { input: "X" input: "W" input: "b" output: "Y" name: "" type: "FC" }
如您在上面的清单中看到的,它首先定义了运算符 X、W 和 b。让我们以 W 的定义为例进行检查。W 的类型指定为 GausianFill。均值 定义为浮点数 0.0,标准差定义为浮点数 1.0,形状 为 5 x 3。
op { output: "W" name: "" type: "GaussianFill" arg { name: "mean" f: 0.0 } arg { name: "std" f: 1.0 } arg { name: "shape" ints: 5 ints: 3 } ... }
检查 X 和 b 的定义,以便您自己理解。最后,让我们看看我们的单层网络的定义,它在此处重现
op { input: "X" input: "W" input: "b" output: "Y" name: "" type: "FC" }
此处,网络类型为 FC(全连接),输入为 X、W、b,输出为 Y。此网络定义过于冗长,对于大型网络而言,检查其内容将变得乏味。幸运的是,Caffe2 为创建的网络提供了图形表示。
网络图形表示
要获取网络的图形表示,请运行以下代码片段,它实际上只有两行 Python 代码。
from caffe2.python import net_drawer from IPython import display graph = net_drawer.GetPydotGraph(net, rankdir="LR") display.Image(graph.create_png(), width=800)
运行代码时,您将看到以下输出 −
对于大型网络,图形表示在可视化和调试网络定义错误方面非常有用。
最后,现在是时候运行网络。
运行网络
您可以通过在 workspace 对象上调用 RunNetOnce 方法来运行网络 −
workspace.RunNetOnce(net)
网络运行一次后,我们随机生成的所有数据都将被创建,输入到网络中并创建输出。运行网络后创建的张量在 Caffe2 中称为 blobs。工作区由您创建并存储在内存中的 blobs 组成。这与 Matlab 非常相似。
运行网络后,您可以使用以下 print 命令检查工作区包含的 blobs
print("工作区中的 Blob:{}".format(workspace.Blobs()))
您将看到以下输出 −
工作区中的 Blob:['W', 'X', 'Y', 'b']
请注意,工作区由三个输入 blob − X、W 和 b 组成。它还包含名为 Y 的输出 blob。现在让我们检查一下这些 blob 的内容。
for name in working.Blobs(): print("{}: {}".format(name, working.FetchBlob(name)))
您将看到以下输出 −
W: [[ 1.0426593 0.15479846 0.25635982] [-2.2461145 1.4581774 0.16827184] [-0.12009818 0.30771437 0.00791338] [ 1.2274994 -0.903331 -0.68799865] [ 0.30834186 -0.53060573 0.88776857]] X: [[ 1.6588869e+00 1.5279824e+00 1.1889904e+00] [ 6.7048723e-01 -9.7490678e-04 2.5114202e-01]] Y: [[ 3.2709925 -0.297907 1.2803618 0.837985 1.7562964] [ 1.7633215 -0.4651525 0.9211631 1.6511179 1.4302125]] b: [1. 1. 1. 1. 1.]
请注意,由于所有输入都是随机创建的,因此您机器上的数据或实际上每次运行网络时的数据都会有所不同。现在您已成功定义网络并在计算机上运行它。