从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

简介:

雷锋网(公众号:雷锋网)按:本文作者姚健,毕业于中科院计算所网络数据实验室,曾就职于360天眼实验室,主要从事深度学习和增强学习相关研究工作。目前就职于腾讯MIG事业部,从事神经机器翻译工作。

摘要

2015年11月9日,Google发布深度学习框架TensorFlow并宣布开源,并迅速得到广泛关注,在图形分类、音频处理、推荐系统和自然语言处理等场景下都被大面积推广。TensorFlow系统更新快速,官方文档教程齐全,上手快速且简单易用,支持Python和C++接口。本文依据对Tensorflow(简称TF)白皮书[1]、TF Github[2]和TF官方教程[3]的理解,从系统和代码实现角度讲解TF的内部实现原理。以Tensorflow r0.8.0为基础,本文由浅入深的阐述Tensor和Flow的概念。先介绍了TensorFlow的核心概念和基本概述,然后剖析了OpKernels模块、Graph模块、Session模块。

1. TF系统架构

1.1 TF依赖视图

TF的依赖视图如图1所示[4],描述了TF的上下游关系链。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图 1 TensorFlow依赖视图

TF托管在github平台,有google groups和contributors共同维护。

TF提供了丰富的深度学习相关的API,支持Python和C/C++接口。

TF提供了可视化分析工具Tensorboard,方便分析和调整模型。

TF支持Linux平台,Windows平台,Mac平台,甚至手机移动设备等各种平台。

1.2 TF系统架构

图2是TF的系统架构,从底向上分为设备管理和通信层、数据操作层、图计算层、API接口层、应用层。其中设备管理和通信层、数据操作层、图计算层是TF的核心层。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图2 TF系统架构

底层设备通信层负责网络通信和设备管理。设备管理可以实现TF设备异构的特性,支持CPU、GPU、Mobile等不同设备。网络通信依赖gRPC通信协议实现不同设备间的数据传输和更新。

第二层是Tensor的OpKernels实现。这些OpKernels以Tensor为处理对象,依赖网络通信和设备内存分配,实现了各种Tensor操作或计算。Opkernels不仅包含MatMul等计算操作,还包含Queue等非计算操作,这些将在第5章Kernels模块详细介绍。

第三层是图计算层(Graph),包含本地计算流图和分布式计算流图的实现。Graph模块包含Graph的创建、编译、优化和执行等部分,Graph中每个节点都是OpKernels类型表示。关于图计算将在第6章Graph模块详细介绍。

第四层是API接口层。Tensor C API是对TF功能模块的接口封装,便于其他语言平台调用。

第四层以上是应用层。不同编程语言在应用层通过API接口层调用TF核心功能实现相关实验和应用。

1.3 TF代码目录组织

图3是TF的代码结构视图,下面将简单介绍TF的目录组织结构。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图3 TF代码目录组织结构

Tensorflow/core目录包含了TF核心模块代码。

  • public: API接口头文件目录,用于外部接口调用的API定义,主要是session.h 和tensor_c_api.h。

  • client: API接口实现文件目录。

  • platform: OS系统相关接口文件,如file system, env等。

  • protobuf: 均为.proto文件,用于数据传输时的结构序列化.

  • common_runtime: 公共运行库,包含session, executor, threadpool, rendezvous, memory管理, 设备分配算法等。

  • distributed_runtime: 分布式执行模块,如rpc session, rpc master, rpc worker, graph manager。

  • framework: 包含基础功能模块,如log, memory, tensor

  • graph: 计算流图相关操作,如construct, partition, optimize, execute等

  • kernels: 核心Op,如matmul, conv2d, argmax, batch_norm等

  • lib: 公共基础库,如gif、gtl(google模板库)、hash、histogram等。

  • ops: 基本ops运算,ops梯度运算,io相关的ops,控制流和数据流操作

  • Tensorflow/stream_executor目录是并行计算框架,由google stream executor团队开发。

  •  Tensorflow/contrib目录是contributor开发目录。

  • Tensroflow/python目录是python API客户端脚本。

  • Tensorflow/tensorboard目录是可视化分析工具,不仅可以模型可视化,还可以监控模型参数变化。

  • third_party目录是TF第三方依赖库。

  • eigen3: eigen矩阵运算库,TF基础ops调用

  • gpus: 封装了cuda/cudnn编程库

2. TF核心概念

TF的核心是围绕Graph展开的,简而言之,就是Tensor沿着Graph传递闭包完成Flow的过程。所以在介绍Graph之前需要讲述一下符号编程、计算流图、梯度计算、控制流的概念。

2.1 Tensor

在数学上,Matrix表示二维线性映射,Tensor表示多维线性映射,Tensor是对Matrix的泛化,可以表示1-dim、2-dim、N-dim的高维空间。图4对比了矩阵乘法(Matrix Product)和张量积(Tensor Contract),可以看出Tensor的泛化能力,其中张量积运算在TF的MatMul和Conv2D运算中都有用到。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图4 Tensor contract

Tensor在高维空间数学运算比Matrix计算复杂,计算量也非常大,加速张量并行运算是TF优先考虑的问题,如add, contract, slice, reshape, reduce, shuffle等运算。

TF中Tensor的维数描述为阶,数值是0阶,向量是1阶,矩阵是2阶,以此类推,可以表示n阶高维数据。

TF中Tensor支持的数据类型有很多,如tf.float16, tf.float32, tf.float64, tf.uint8, tf.int8, tf.int16, tf.int32, tf.int64, tf.string, tf.bool, tf.complex64等,所有Tensor运算都使用泛化的数据类型表示。

TF的Tensor定义和运算主要是调用Eigen矩阵计算库完成的。TF中Tensor的UML定义如图4。其中TensorBuffer指针指向Eigen::Tensor类型。其中,Eigen::Tensor[5][6]不属于Eigen官方维护的程序,由贡献者提供文档和维护,所以Tensor定义在Eigen unsupported模块中。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图5 Tensor数据结构定义

图5中,Tensor主要包含两个变量m_data和m_dimension,m_data保存了Tensor的数据块,T是泛化的数据类型,m_dimensions保存了Tensor的维度信息。

Eigen:Tensor的成员变量很简单,却支持非常多的基本运算,再借助Eigen的加速机制实现快速计算,参考章节3.2。Eigen::Tensor主要包含了

  • 一元运算(Unary),如sqrt、square、exp、abs等。

  • 二元运算(Binary),如add,sub,mul,div等

  • 选择运算(Selection),即if / else条件运算

  • 归纳运算(Reduce),如reduce_sum, reduce_mean等

  • 几何运算(Geometry),如reshape,slice,shuffle,chip,reverse,pad,concatenate,extract_patches,extract_image_patches等

  • 张量积(Contract)和卷积运算(Convolve)是重点运算,后续会详细讲解。

2.2 符号编程

编程模式通常分为命令式编程(imperative style programs)和符号式编程(symbolic style programs)。

命令式编程容易理解和调试,命令语句基本没有优化,按原有逻辑执行。符号式编程涉及较多的嵌入和优化,不容易理解和调试,但运行速度有同比提升。

这两种编程模式在实际中都有应用,Torch是典型的命令式风格,caffe、theano、mxnet和Tensorflow都使用了符号式编程。其中caffe、mxnet采用了两种编程模式混合的方法,而Tensorflow是完全采用了符号式编程,Theano和Tensorflow的编程模式更相近。

命令式编程是常见的编程模式,编程语言如python/C++都采用命令式编程。命令式编程明确输入变量,并根据程序逻辑逐步运算,这种模式非常在调试程序时进行单步跟踪,分析中间变量。举例来说,设A=10, B=10,计算逻辑:

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

第一步计算得出C=100,第二步计算得出D=101,输出结果D=101。

符号式编程将计算过程抽象为计算图,计算流图可以方便的描述计算过程,所有输入节点、运算节点、输出节点均符号化处理。计算图通过建立输入节点到输出节点的传递闭包,从输入节点出发,沿着传递闭包完成数值计算和数据流动,直到达到输出节点。这个过程经过计算图优化,以数据(计算)流方式完成,节省内存空间使用,计算速度快,但不适合程序调试,通常不用于编程语言中。举上面的例子,先根据计算逻辑编写符号式程序并生成计算图

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

其中A和B是输入符号变量,C和D是运算符号变量,compile函数生成计算图F,如图6所示。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图6 符号编程的正向计算图

最后得到A=10, B=10时变量D的值,这里D可以复用C的内存空间,省去了中间变量的空间存储。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图 6是TF中的计算流图,C=F(Relu(Add(MatMul(W, x), b))),其中每个节点都是符号化表示的。通过session创建graph,在调用session.run执行计算。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图7 TF符号计算图

和目前的符号语言比起来,TF最大的特点是强化了数据流图,引入了mutation的概念。这一点是TF和包括Theano在内的符号编程框架最大的不同。所谓mutation,就是可以在计算的过程更改一个变量的值,而这个变量在计算的过程中会被带入到下一轮迭代里面去。

Mutation是机器学习优化算法几乎必须要引入的东西(虽然也可以通过immutable replacement来代替,但是会有效率的问题)。 Theano的做法是引入了update statement来处理mutation。TF选择了纯符号计算的路线,并且直接把更新引入了数据流图中去。从目前的白皮书看还会支持条件和循环。这样就几乎让TF本身成为一门独立的语言。不过这一点会导致最后的API设计和使用需要特别小心,把mutation 引入到数据流图中会带来一些新的问题,比如如何处理写与写之间的依赖。[7]

2.3 梯度计算

梯度计算主要应用在误差反向传播和数据更新,是深度学习平台要解决的核心问题。梯度计算涉及每个计算节点,每个自定义的前向计算图都包含一个隐式的反向计算图。从数据流向上看,正向计算图是数据从输入节点到输出节点的流向过程,反向计算图是数据从输出节点到输入节点的流向过程。

图8是2.2节中图6对应的反向计算图。图中,由于C=A*B,则dA=B*dC, dB=A*dC。在反向计算图中,输入节点dD,输出节点dA和dB,计算表达式为dA=B*dC=B*dD, dB=A*dC=A*dD。每一个正向计算节点对应一个隐式梯度计算节点。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图8 符号编程的反向计算图

反向计算限制了符号编程中内存空间复用的优势,因为在正向计算中的计算数据在反向计算中也可能要用到。从这一点上讲,粗粒度的计算节点比细粒度的计算节点更有优势,而TF大部分为细粒度操作,虽然灵活性很强,但细粒度操作涉及到更多的优化方案,在工程实现上开销较大,不及粗粒度简单直接。在神经网络模型中,TF将逐步侧重粗粒度运算。

2.4 控制流

TF的计算图如同数据流一样,数据流向表示计算过程,如图9。数据流图可以很好的表达计算过程,为了扩展TF的表达能力,TF中引入控制流。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

图9 Graph的数据流

在编程语言中,if…else…是最常见的逻辑控制,在TF的数据流中也可以通过这种方式控制数据流向。接口函数如下,pred为判别表达式,fn1和fn2为运算表达式。当pred为true是,执行fn1操作;当pred为false时,执行fn2操作。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

TF还可以协调多个数据流,在存在依赖节点的场景下非常有用,例如节点B要读取模型参数θ更新后的值,而节点A负责更新参数θ,则节点B必须等节点A完成后才能执行,否则读取的参数θ为更新前的数值,这时需要一个运算控制器。接口函数如下,tf.control_dependencies函数可以控制多个数据流执行完成后才能执行接下来的操作,通常与tf.group函数结合使用。

从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度

TF支持的控制算子有Switch、Merge、Enter、Leave和NextIteration等。

TF不仅支持逻辑控制,还支持循环控制。TF使用和MIT Token-Tagged machine相似的表示系统,将循环的每次迭代标记为一个tag,迭代的执行状态标记为一个frame,但迭代所需的数据准备好的时候,就可以开始计算,从而多个迭代可以同时执行。

未完待续……

本文作者:深度学习大讲堂

本文转自雷锋网禁止二次转载,原文链接

相关文章
|
11月前
|
算法 PyTorch 算法框架/工具
昇腾 msmodelslim w8a8量化代码解析
msmodelslim w8a8量化算法原理和代码解析
912 5
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
1174 55
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
520 94
|
11月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【害虫识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
害虫识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了12种常见的害虫种类数据集【"蚂蚁(ants)", "蜜蜂(bees)", "甲虫(beetle)", "毛虫(catterpillar)", "蚯蚓(earthworms)", "蜚蠊(earwig)", "蚱蜢(grasshopper)", "飞蛾(moth)", "鼻涕虫(slug)", "蜗牛(snail)", "黄蜂(wasp)", "象鼻虫(weevil)"】 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Djan
632 1
基于Python深度学习的【害虫识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
|
12月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【蘑菇识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
蘑菇识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了9种常见的蘑菇种类数据集【"香菇(Agaricus)", "毒鹅膏菌(Amanita)", "牛肝菌(Boletus)", "网状菌(Cortinarius)", "毒镰孢(Entoloma)", "湿孢菌(Hygrocybe)", "乳菇(Lactarius)", "红菇(Russula)", "松茸(Suillus)"】 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,
1169 11
基于Python深度学习的【蘑菇识别】系统~卷积神经网络+TensorFlow+图像识别+人工智能
|
11月前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
438 5
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
636 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
12月前
|
人工智能 文字识别 自然语言处理
保单AI识别技术及代码示例解析
车险保单包含基础信息、车辆信息、人员信息、保险条款及特别约定等关键内容。AI识别技术通过OCR、文档结构化解析和数据校验,实现对保单信息的精准提取。然而,版式多样性、信息复杂性、图像质量和法律术语解析是主要挑战。Python代码示例展示了如何使用PaddleOCR进行保单信息抽取,并提出了定制化训练、版式分析等优化方向。典型应用场景包括智能录入、快速核保、理赔自动化等。未来将向多模态融合、自适应学习和跨区域兼容性发展。
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
778 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
4123 11

推荐镜像

更多
  • DNS