目录

  1. 核心概念
  2. device
  3. device_factory
  4. device_mgr
  5. device_set

1. 核心概念

在framework部分,我们介绍了DeviceAttributes和DeviceBase两个结构,这些其实是为了我们今天要介绍的Device类做准备的。感兴趣的读者可以去回顾下前面讲过的内容。Device类只是对DeviceBase类的继承,没有添加更多新的数据成员,但提供了Compute计算接口。DeviceSet是一个设备集合类,而DeviceMgr与DeviceSet的不同点在于,它提供了设备管理的功能,为设备查找和计数提供了便利的数据结构。最后,DeviceFactory是为了产生某种类型的设备准备的工厂类,同样的设备类型(比如CPU)会对应不同的工厂,意味着不同的实现,而不同的工厂有着不同的权重。这里的权重是为了辅助我们选择某种类型的设备用的。

2. device

Device类,除了包含对内部私有数据的访问API之外,还包含了核心的计算API Compute,我们先来看一下它的结构:

class Device : public DeviceBase {
public:
virtual void Compute(OpKernel* op_kernel, OpKernelContext* context){
op_kernel->Compute(context);
}
virtual void ComputeAsync(AsyncOpKernel* op_kernel, OpKernelContext* context, AsyncOpKernel::DoneCallback done){
op_kernel->ComputeAsync(context, std::move(done));
}
//...
private:
const DeviceAttributes device_attributes_;
DeviceNameUtils::ParsedName parsed_name_;
OpSegment op_seg_;
ResourceMgr* rmgr_ = nullptr;
}

TF对于设备名称是有要求的,它必须满足这种格式:/job:_/replica:_/task:_/(gpu|cpu):_,举个例子:/job:train/replica:0/task:3/gpu:2。其中,Device类的数据成员parsed_name_就是对这种设备名称的拆解,感兴趣的读者可以自行看下ParsedName的定义。ResourceMgr和OpSegment我们之前在framework部分也都介绍过了。所以从数据角度讲,Device没有什么新鲜的,只是对原有的关于设备的数据做了一个整合。但从API的角度讲,它包含了一个计算接口Compute,实际上也就是对OpKernel中的Compute接口的封装。

3. device_set

DeviceSet是一个容器类,用于管理一个模型使用的不同设备。这个类相对比较简单,我们看它的结构:

class DeviceSet {
public:
//...
private:
std::vector<Device*> devices_;
std::unordered_map<string, Device*> device_by_name_;
Device* client_device_ = nullptr;
}

其中,device_by_name_是一个从设备全称到设备指针的映射,而client_device_是我们从devices_中挑选的,默认的客户端设备。

4. device_mgr

DeviceMgr顾名思义是一个设备管理类,其实它主要是提供了一系列数据结构来提高API的效率,比如,我们要查找一个给定设备名的设备指针,或者要对某种类型的设备计数。针对这种高频操作,DeviceMgr为其准备了高效的数据结构。类的结构如下:

class DeviceMgr {
public:
//...
private:
typedef gtl::InlinedVector<Device*, 8> DeviceVec;
DeviceVec devices_;
std::unordered_map<StringPiece, Device*, StringPiece::Hasher> device_map_;
core::Arena name_backing_store_;
std::unordered_map<string, int> device_type_counts_;
}

device_map_是为了提高查找指定名称的设备的效率,device_type_counts_是为了提高查找指定类型的设备数的效率。

5. DeviceFactory

正如刚才提到过的,DeviceFactory代表了某种设备(比如CPU)的某种实现的工厂类。下面我们看下DeviceFactory类的结构:

class DeviceFactory {
public:
static void Register(const string& device_type, DeviceFactory* factory, int priority);
static DeviceFactory* GetFactory(const string& device_type);
static Status AddDevices(const SessionOptions& options, const string& name_prefix, std::vector<Device*>* devices);
static Device* NewDevice(const string& type, const SessionOptions& options, const string& name_prefix);
virtual Status CreateDevices(const SessionOptions& options, const string& name_prefix, std::vector<Device*>* devices) = 0;
static int32 DevicePriority(const string& device_type);
};

看完这个类,我们感觉很疑惑,它提供了很多的API,但是没有数据成员,那它注册的那些工厂,存储在哪里呢?

别慌,我们在device_factory.cc文件中,找到了这样的定义:

struct FactoryItem {
std::unique_ptr<DeviceFactory> factory;
int priority;
};
std::unordered_map<string, FactoryItem>& device_factories(){
static std::unordered_map<string, FactoryItem>* factories = new std::unordered_map<string, FactoryItem>;
return *factories;
}

对于第二个函数,它内部定义了一个静态成员,因此相当于提供了一个全局的从设备类型名称到其生产工厂的映射。每当我们需要这个映射时,就调用这个函数。实际上,DeviceFactory的很多成员函数,就是这样实现的。

另外,TF还提供了一个Registrar类,为DeviceFactory提供了注册的入口:

template<class Factory> class Registrar {
public:
explicit Registrar(const string& device_type, int priority=50){
DeviceFactory::Register(device_type, new Factory(), priority);
}
};

它实际上是为某种设备类型注册其设备工厂。

关于设备工厂类,我们在代码中经常看到priority,对于权重,我们详细说明一下:

  • 对于同样一种设备类型,不同的注册可以由不同的权重,即同一个设备类型的不同实现,可以拥有不同的权重。权重主要被应用于以下两个方面:
  • (接上)第一,当我们需要为某一个特定的设备类型选择工厂时,拥有最高权重的工厂将会被选择。例如,如果有如下的两种注册信息

    Registrar<CPUFactory1>("CPU", 125);

    Registrar<CPUFactory2>("CPU", 150);

    那么当调用DeviceFactory::GetFactory("CPU")时,CPUFactory2将会被返回。
  • (接上)第二,当需要在DeviceSet中选择一种设备类型时,选择的顺序由权重priority决定。例如,对于以下的两种注册:

    Registrar<CPUFactory>("CPU",100);

    Registrar<GPUFactory>("GPU",200);

    则DeviceType("GPU")将会被优先选择。
  • 不同设备的默认权重如下:GPU:200,SYCL:200,GPUCompatibleCPU:70,ThreadPoolDevice:60,Default:50

tensorflow源码解析之common_runtime-device的更多相关文章

  1. tensorflow源码解析之common_runtime拾遗

    把common_runtime中剩余的内容,按照文件名排序进行了简单的解析,时间原因写的很仓促,算是占个坑,后续有了新的理解再来补充. allocator_retry 有时候内存分配不可能一次完成,为 ...

  2. tensorflow源码解析系列文章索引

    文章索引 framework解析 resource allocator tensor op node kernel graph device function shape_inference 拾遗 c ...

  3. Tensorflow源码解析1 -- 内核架构和源码结构

    1 主流深度学习框架对比 当今的软件开发基本都是分层化和模块化的,应用层开发会基于框架层.比如开发Linux Driver会基于Linux kernel,开发Android app会基于Android ...

  4. tensorflow源码解析之framework拾遗

    把framework中剩余的内容,按照文件名进行了简单解析.时间原因写的很仓促,算是占个坑,后面有了新的理解再来补充. allocation_description.proto 一个对单次内存分配结果 ...

  5. tensorflow源码解析之common_runtime-executor-上

    目录 核心概念 executor.h Executor NewLocalExecutor ExecutorBarrier executor.cc structs GraphView ExecutorI ...

  6. tensorflow源码解析之common_runtime-executor-下

    目录 核心概念 executor.h Executor NewLocalExecutor ExecutorBarrier executor.cc structs GraphView ExecutorI ...

  7. tensorflow源码解析之framework-allocator

    目录 什么是allocator 内存分配器的管理 内存分配追踪 其它结构 关系图 涉及的文件 迭代记录 1. 什么是allocator Allocator是所有内存分配器的基类,它定义了内存分配器需要 ...

  8. Tensorflow源码解析2 -- 前后端连接的桥梁 - Session

    Session概述 1. Session是TensorFlow前后端连接的桥梁.用户利用session使得client能够与master的执行引擎建立连接,并通过session.run()来触发一次计 ...

  9. tensorflow源码解析之distributed_runtime

    本篇主要介绍TF的分布式运行时的基本概念.为了对TF的分布式运行机制有一个大致的了解,我们先结合/tensorflow/core/protobuf中的文件给出对TF分布式集群的初步理解,然后介绍/te ...

  10. tensorflow源码解析之framework-op

    目录 什么是op op_def定义 op注册 op构建与注册辅助结构 op重写 关系图 涉及的文件 迭代记录 1. 什么是op op和kernel是TF框架中最重要的两个概念,如果一定要做一个类比的话 ...

随机推荐

  1. 物理CPU,物理核,逻辑CPU,虚拟CPU(vCPU)区别 (转)

    在做虚拟化时候,遇到划分CPU的问题,因此考虑到CPU不知道具体怎么划分,查询一些资料后就写成本文. a. 物理CPU:物理CPU是相对于虚拟CPU而言的概念,指实际存在的处理器,就是我们可以看的见, ...

  2. SpringBoot使用IDEA设置的外部Tomcat启动

    前言 使用springboot内嵌的tomcat启动是没问题,但是工程是要放到服务器上的tomcat的,所以springboot内嵌的能够启动,但不代表服务器的tomcat能启动起来,我就遇到了这个问 ...

  3. argc 和 argv

    转载请注明来源:https://www.cnblogs.com/hookjc/ 如果用C寫一般的命令列工具,常透過main函式的argc,argv來取得使用者所輸入的命令參數.int main(int ...

  4. K8s 部署 Dashboard UI 仪表板 ——让一切可视化

    K8s 部署 Dashboard UI  仪表板   --让一切可视化 Dashboard 介绍 仪表板是基于Web的Kubernetes用户界面.您可以使用仪表板将容器化应用程序部署到Kuberne ...

  5. 基于TI DSP TMS320C6455、Xilinx V5 FPGA XC5VSX95T的高速数据处理核心板

    一.板卡概述 该DSP+FPGA高速信号采集处理板由我公司自主研发,包含一片TI DSP TMS320C6455和一片Xilinx V5 FPGA XC5VSX95T-1FF1136i.包含1个千兆网 ...

  6. Solution -「SHOI2016」「洛谷 P4336」黑暗前的幻想乡

    \(\mathcal{Description}\)   link.   有一个 \(n\) 个结点的无向图,给定 \(n-1\) 组边集,求从每组边集选出恰一条边最终构成树的方案树.对 \(10^9+ ...

  7. Linux性能优化之内存性能调优

    一.根据性能指标找工具 二.根据工具查性能 三.内存优化策略 常见的优化思路有这么几种: 1)最好禁止 Swap.如果必须开启 Swap,降低 swappiness 的值,减少内存回收时 Swap 的 ...

  8. Eureka工作原理及心跳机制

    Eureka原理 1.基本原理上图是来自eureka的官方架构图,这是基于集群配置的eureka:处于不同节点的eureka通过Replicate进行数据同步Application Service为服 ...

  9. spring的事务是如何回滚的、事务传播?

    实际上也是问的这个问题  spring的事务管理是如何实现的?总: spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况下要通过通知来 ...

  10. Asp.net core IdentityServer4与传统基于角色的权限系统的集成

    写在前面 因为最近在忙别的,好久没水文了 今天来水一篇: 在学习或者做权限系统技术选型的过程中,经常有朋友有这样的疑问 : "IdentityServer4的能不能做到与传统基于角色的权限系 ...