TensorFlow除了大量使用Eigen和CUDA等计算库函数之外,还大量使用了Proto Buffer。Proto Buffer是一个数据传输协议,它可以将C++,Python和Java创建的对象序列化为二进制文件。这样,我们可以很轻松地实现在不同的设备上运行的用不同编程语言实现的不同进程之间,实现数据传送。
但是,并非所有的对象,都可以用Proto Buffer传输。要使用Proto Buffer这些对象的类型必须满足特定的要求。确切地说,数据类型必须实现序列化和反序列函数。我们把实现了序列化和反序列化函数的类称作是Proto Buffer类。编写这两个函数通常是繁琐无聊的操作。所幸的是,Google提供了一个工具,自动生成Proto Buffer类。具体来说,我们先用Proto Buffer语言定义消息类型,然后再利用Proto Buffer工具,生成特定编程语言的类。
TensorFlow的DeviceAttributes类就是Proto Buffer类型。顾名思义,它是定义设备属性的类。它的Proto Buffer消息类型定义在tensorflow/core/framework/device_attributes.proto中。
message DeviceAttributes {
// Fully specified name of the device within a cluster.
string name = 1;
// String representation of device_type.
string device_type = 2;
// Memory capacity of device in bytes.
int64 memory_limit = 4;
// Platform-specific data about device that may be useful
// for supporting efficient data transfers.
DeviceLocality locality = 5;
// A device is assigned a global unique number each time it is
// initialized. "incarnation" should never be 0.
fixed64 incarnation = 6;
// String representation of the physical device that this device maps to.
string physical_device_desc = 7;
}
第1行的message关键字表示我们要定义一个新的消息类型,它类似于C++的class或者struct关键字。后面紧跟的DeviceAtrributes是消息类型名。类名后一对花括号包含的部分定义了这个消息类的成员变量。
第3行定义了一个名字为name的变量,它的是类型为string,即一个字符串类型。string是proto buffer内置的一个数据类型。类似地fixed64也是一个内置类型,代表一个64位整数。int64也是一个内置的64位整数。与fixed64不同的是,int64的位数最多是64位(当数值小的时候,可以小于64位),而fixed64的位数始终是64位。
第13行的DeviceLocality是一个自定义的消息类型,关于该类型的定义稍后再说。
这里还需要特别说明的是每个成员变量都需要被赋予一个唯一的序号。例如string name = 1就表示name的序号为1。这个序号定义了各个变量序列化的顺序。序号越小的变量,会首先被序列化。因此,对于DeviceAtrributes类来说,首先被序列化的是name, 其次device_type,以此类推。
DeviceLocality类定义在相同的文件中。
message DeviceLocality {
// Optional bus locality of device. Default value of 0 means
// no specific locality. Specific localities are indexed from 1.
int32 bus_id = 1;
// Optional NUMA locality of device.
int32 numa_node = 2;
// Optional local interconnect links to other devices.
LocalLinks links = 3;
};
这个类中,使用了另外一个自定义类型LocalLinks,它也定义在相同文件中。
message LocalLinks {
repeated InterconnectLink link = 1;
};
这个类中有一个新的关键字repeated。顾名思义,它意味着link成员变量可能有多个。也就是说,这个成员变量是一个变长的数组,数组长度可能为0,而数组元素的数据类型由repeated关键字后面的InterConnectLink指定,它也是一个自定义的数据类型。
message InterconnectLink {
int32 device_id = 1;
string type = 2;
int32 strength = 3;
};