【windows源码反汇编】【仿货拉拉 源码】【zip压缩算法源码】tf源码分析

1.TFlite 源码分析(一) 转换与量化
2.ONNX一本通:综述&使用&源码分析(持续更新)
3.tf.embedding_lookup(sparse)详解
4.探索TensorFlow核心组件系列之Session的源码运行源码分析
5.Cartographer源码详解|(2)Cartographer_ros
6.从源码build Tensorflow2.6.5的记录

tf源码分析

TFlite 源码分析(一) 转换与量化

       TensorFlow Lite 是 Google 推出的用于设备端推断的开源深度学习框架,其主要目的分析是将 TensorFlow 模型部署到手机、嵌入式设备或物联网设备上。源码它由两部分构成:模型转换工具和模型推理引擎。分析

       TFLite 的源码核心组成部分是转换(Converter)和解析(interpreter)。转换主要负责将模型转换成 TFLite 模型,分析windows源码反汇编并完成优化和量化的源码过程。解析则专注于高效执行推理,分析在端侧设备上进行计算。源码

       转换部分,分析主要功能是源码通过 TFLiteConverter 接口实现。转换过程涉及确定输入数据类型,分析如是源码否为 float、int8 或 uint8。分析优化和转换过程主要通过 Toco 完成,源码包括导入模型、模型优化、转换以及输出模型。

       在导入模型时,`ImportTensorFlowGraphDef` 函数负责确定输入输出节点,并检查所有算子是否支持,同时内联图的节点进行转换。量化过程则涉及计算网络中单层计算的量化公式,通常针对 UINT8(范围为 0-)或 INT8(范围为 -~)。量化功能主要通过 `CheckIsReadyForQuantization`、`Quantize` 等函数实现,确保输入输出节点的最大最小值存在。

       输出模型时,根据指定的输出格式(如 TensorFlow 或 TFLite)进行。TFLite 输出主要分为数据保存和创建 TFLite 模型文件两部分。

       量化过程分为选择量化参数和计算量化参数两部分。选择量化参数包括为输入和权重选择合适的量化参数,这些参数在 `MakeInitialDequantizeOperator` 中计算。计算参数则使用 `ChooseQuantizationParamsForArrayAndQuantizedDataType` 函数,该函数基于模板类模板实现。

       TFLite 支持的量化操作包括 Post-training quantization 方法,实现相关功能的代码位于 `tools\optimize\quantize_model.cc`。

ONNX一本通:综述&使用&源码分析(持续更新)

       ONNX详解:功能概述、Python API应用与源码解析

       ONNX的核心功能集中在模型定义、算子操作、序列化与反序列化,以及模型验证上。它主要通过onnx-runtime实现运行时支持,包括图优化和平台特定的算子库。模型转换工具如tf、pytorch和mindspore的FMK工具包负责各自框架模型至ONNX的转换。

       ONNX Python API实战

       场景一:构建线性回归模型,基础操作演示了API的使用。

       场景二至四:包括为op添加常量参数、属性以及控制流(尽管控制流在正式模型中应尽量避免)。

       场景五和后续:涉及for循环和自定义算子的仿货拉拉 源码添加,如Cos算子,涉及算子定义、添加到算子集、Python实现等步骤。

       源码分析

       onnx.checker:负责模型和元素的检查,cpp代码中实现具体检查逻辑。

       onnx.compose、onnx.defs、onnx.helper等:提供模型构建、算子定义和辅助函数。

       onnx.numpy_helper:处理numpy数组与onnx tensor的转换。

       onnx.reference:提供Python实现的op推理功能。

       onnx.shape_inference:进行模型的形状推断。

       onnx.version_converter:处理不同op_set_version的转换。

       转换实践

       ONNX支持将tf、pytorch和mindspore的模型转换为ONNX格式,同时也有ONNX到TensorRT、MNN和MS-Lite等其他格式的转换选项。

       总结

       ONNX提供了一个统一的IR(中间表示)框架,通过Python API构建模型,支持算子定义的检查和模型的序列化。同时,它利用numpy实现基础算子,便于模型的正确性验证,并支持不同框架模型之间的转换。

tf.embedding_lookup(sparse)详解

       嵌入查找是一种从矩阵中根据ID索引对应值的方法,适用于处理离散特征。

       假设embw1为一个行5列的矩阵,即表示一个拥有个类别的单值离散特征(例如商品ID)的初始化权重嵌入矩阵,嵌入大小为5。如果feature1是一个序列多值稀疏特征,批量大小为4,序列特征长度为3,经过嵌入查找后,转换为(4,3,5)的张量。这种方法在DIN源码中有所应用。

       如果feature2是单值稀疏特征,批量大小为4,经过嵌入查找后,转换为(4,5)的张量。这表示是从emb_w1的特定行进行行索引。

       第二部分,嵌入查找稀疏主要参考博客,引入了从CSV文件中读取和解析数据的操作。需要注意在CSV解析时,确保每一行前有固定的索引值,否则可能会报错。假设CSV解析的index是固定的使用方法,若采用逐行解析的reader形式,则index是zip压缩算法源码自带的。目前尚未实现使用reader形式解析的博客链接。

       总体而言,嵌入查找和嵌入查找稀疏在处理稀疏数据时,提供了高效的方法来转换和处理特征,为模型训练提供了有力的支持。

探索TensorFlow核心组件系列之Session的运行源码分析

       TensorFlow作为一个前后端分离的计算框架,旨在实现前端在任何设备、任何位置上使用API构建模型,而不受硬件资源限制。那么,TensorFlow是如何建立前后端的连接呢?在这一过程中,Session起着关键桥梁作用,它连接前后端通道,并通过session.run()触发计算,将前端的计算图转化为graphdef pb格式发送至后端。后端接收此格式,将计算图重建、剪枝、分裂,并分配到设备上,最终在多个Executor上执行计算。

       Session管理着计算图、变量、队列、锁、设备和内存等多种资源,确保资源安全、高效地使用。在Session生命周期中,包含创建、运行、关闭和销毁四个阶段,确保模型运行的正确性和效率。

       在Session创建时,使用BaseSession初始化,通过调用TF_NewSessionRef创建实例。此过程涉及确定图实例、判断混合精度设置以及创建Session。在分布式框架中,Python通过swig自动生成的函数符号映射关系调用C++层实现。

       Session运行主要通过session.run()触发,该方法在BaseSession的run()中实现,涉及创建fetch处理器、获取最终fetches和targets,调用_do_run方法启动计算,并输出结果。在本地模式下,Session初始化会生成DirectSession对象。

       综上所述,Session在TensorFlow架构中扮演着核心角色,代超APP源码连接前后端,管理资源,并确保模型高效、安全地运行。

Cartographer源码详解|(2)Cartographer_ros

       上一篇文章深入分析了传感器数据的流向,接下来让我们继续探讨传感器格式的转换与类型变换。这部分内容在sensor_bridge.cc文件中。在处理传感器的坐标变换时,我们需要运用三维空间刚体运动的知识,先进行简要回顾,以助于理解代码。

       三维空间刚体运动涉及向量内积与外积。向量内积的计算公式如下,表示两个向量的点乘。向量外积则是一个向量,其方向垂直于两个向量,大小为两向量张成四边形的有向面积,计算公式如下。

       旋转和平移是欧氏变换的两个关键部分。旋转涉及单位正交基的变换,形成旋转矩阵(Rotation matrix),该矩阵的各分量由两组基之间的内积组成,反映了旋转前后同一向量坐标的变化关系。平移则通过向旋转后的坐标中加入平移向量t实现。通过旋转矩阵R和平移向量t,我们可以完整描述欧氏空间中的坐标变换关系。

       为了简化变换过程,引入齐次坐标和变换矩阵。在三维向量末尾添加1形成四维向量,进行线性变换。变换矩阵T能够将两次变换叠加简化为一个操作,便于后续计算。

       Cartographer的坐标转换程序位于transform文件夹下的rigid_transform中,用于求解变换矩阵的逆。

       在sensor_bridge类中,构造函数将传入配置参数,对里程计数据进行处理。首先将ros时间转换为ICU时间,然后利用tf_bridge_.LookupToTracking函数找到tracking坐标系与里程计child_frame_id之间的坐标变换。在ToOdometryData函数中,将里程计的footprint的pose转换为tracking_frame的pose,并最终将结果转换为carto::sensor::OdometryData的数据类型。

       HandleOdometryMessage函数将传感器数据类型与坐标系转换完成后,调用trajectory_builder_->AddSensorData进行数据处理。对于雷达数据,首先转换为点云格式,然后对点云进行坐标变换,并调用trajectory_builder_->AddSensorData进行数据处理。

       IMU数据处理中,要求平移分量小于1e-5,积分兑换源码赚钱然后调用trajectory_builder_->AddSensorData对数据进行处理。

       在雷达数据处理部分,首先将点云数据分段,然后传给HandleRangefinder处理,将点云坐标变换到tracking_frame坐标系下,调用trajectory_builder_->AddSensorData函数进行数据处理。

       总结本章内容,我们详细解析了SensorBridge类,对传感器数据进行了转换和传输。通过Node类、MapBuilderBridge类和SensorBridge类,我们对Cartographer_ros部分的代码有了基本了解。接下来,我们将深入学习cartographer。

从源码build Tensorflow2.6.5的记录

       .从源码编译Tensorflow2.6.5踩坑记录,笔者经过一天的努力,失败四次后终于成功。Tensorflow2.6.5是截至.时,能够从源码编译的最新版本。

       0 - 前期准备

       为了对Tensorflow进行大规模修改并完成科研工作,笔者有从源码编译Tensorflow的需求。平时更常用的做法是在conda环境中pip install tensorflow,有时为了环境隔离方便打包,会用docker先套住,再上conda + pip安装。

       1 - 资料汇总

       教程参考:

       另注:bazel的编译可以使用换源清华镜像(不是必要)。整体配置流程的根本依据还是官方的教程,但它的教程有些点和坑没有涉及到,所以多方材料了解。

       2 - 整体流程

       2.1 确定配置目标

       官网上给到了配置目标,和对应的版本匹配关系(这张表里缺少了对numpy的版本要求)。笔者最后(在docker中)配置成功的版本为tensorflow2.6.5 numpy1..5 Python3.7. GCC7.5.0 CUDA.3 Bazel3.7.2。

       2.2 开始配置

       为了打包方便和编译环境隔离,在docker中进行了以下配置:

       2. 安装TensorFlow pip软件包依赖项,其编译过程依赖于这些包。

       3. Git Tensorflow源代码包。

       4. 安装编译工具Bazel。

       官网的介绍:(1)您需要安装Bazel,才能构建TensorFlow。您可以使用Bazelisk轻松安装Bazel,并且Bazelisk可以自动为TensorFlow下载合适的Bazel版本。为便于使用,请在PATH中将Bazelisk添加为bazel可执行文件。(2)如果没有Bazelisk,您可以手动安装Bazel。请务必安装受支持的Bazel版本,可以是tensorflow/configure.py中指定的介于_TF_MIN_BAZEL_VERSION和_TF_MAX_BAZEL_VERSION之间的任意版本。

       但笔者尝试最快的安装方式是,到Github - bazelbuild/build/releases上下载对应的版本,然后使用sh脚本手动安装。比如依据刚才的配置目标,笔者需要的是Bazel3.7.2,所以下载的文件为bazel-3.7.2-installer-linux-x_.sh。

       5. 配置编译build选项

       官网介绍:通过运行TensorFlow源代码树根目录下的./configure配置系统build。此脚本会提示您指定TensorFlow依赖项的位置,并要求指定其他构建配置选项(例如,编译器标记)。

       这一步就是选择y/N基本没啥问题,其他参考里都有贴实例。笔者需要GPU的支持,故在CUDA那一栏选择了y,其他部分如Rocm部分就是N(直接按enter也可以)。

       6.开始编译

       编译完成应输出

       7.检查TF是否能用

       3 - 踩坑记录

       3.1 cuda.0在编译时不支持sm_

       笔者最初选择的docker是cuda.0的,在bazel build --config=cuda //tensorflow/tools/pip_package:build_pip_package过程中出现了错误。所以之后选择了上面提到的cuda.3的docker。

       3.2 问题2: numpy、TF、python版本匹配

       在配置过程中,发现numpy、TF、python版本需要匹配,否则会出现错误。

       4 - 启示

       从源码编译Tensorflow2.6.5的过程,虽然经历了多次失败,但最终还是成功。这个过程也让我对Tensorflow的编译流程有了更深入的了解,同时也提醒我在后续的工作中要注意版本匹配问题。

序列化推荐中的GRU与Transformer源码解析之一

       GRU4Rec源码(TF版本):github.com/Songweiping/...

       Transformer源码:github.com/kang/SASR...

       序列化推荐领域中,GRU4Rec成功地将循环神经网络(NLP和时序预测常用)应用至推荐领域,此模型取得了良好效果。紧随其后的是"SASR",基于注意力机制的自适应序列推荐模型,实验表明其性能超越了GRU4Rec。

       两篇论文的作者均在源码公开阶段,为研究者提供参考。我们深入剖析源码,后续系列文章将比较GRU4Rec与SASR的差异、联系与优缺点。

       GRU4Rec模型结构简洁,采用门限循环神经网络,Embedding层处理item_id的one_hot编码,降低维度,便于优化。

       并行化训练数据集优化了模型训练速度,构建了training_batch,便于使用GPU加速矩阵运算。

       负采样技术提高了训练频率,利用同一时刻不同session中的item作为负样本。

       模型设计了贝叶斯排序和TOP1等pairwise方法计算排序损失,认为pairwise结果优于pointwise。

       实验数据集包括RSC和私有VIDEO集,结果表明GRU4Rec模型性能优秀,测试集评价指标包括召回率(recall)和倒序排名得分(mrr)。

       深入分析模型的Tensorflow版本代码,主要从main.py和model.py文件开始,重点解析模型定义、损失函数、GRU4Rec核心代码、数据集初始化、模型训练与预测以及评估函数。

       GRU4Rec的代码分析暂告一段落,后续将详细梳理SASR代码,目标是通过三篇文章全面探讨两个模型的细节。感谢关注。

Dive into TensorFlow系列(1)-静态图运行原理

       接触过TensorFlow v1的朋友都知道,训练一个TF模型有三个步骤:定义输入和模型结构,创建tf.Session实例sess,执行sess.run()启动训练。不管是因为历史遗留代码或是团队保守的建模规范,其实很多算法团队仍在大量使用TF v1进行日常建模。但背后的运行原理大家是否清楚呢?今天让我们一起来探个究竟。

       学习静态图运行原理能干什么?掌握它对我们TF实践中的错误排查、程序定制、性能优化至关重要,是必备的前置知识。

一、何为静态图?

       众所周知,TensorFlow程序有两种运行选择,即静态图模式与动态图模式。

1.1 静态图

       静态图采用声明式编程范式(先编译后执行),根据前端语言(如python)描述的神经网络结构和参数信息构建固定的静成计算图。静态图在执行期间不依赖前端语言,而是由TF框架负责调度执行,因此非常适合做神经网络模型的部署。用户定义的静态图经序列化后用GraphDef表达,其包含的信息有:网络连接、参数设置、损失函数、优化器等。

       有了完整的静态图定义后,TF编译器将计算图转化成IR(中间表示)。初始IR会经TF编译器一系列的转换和优化策略生成等价的计算图。编译器前端转换和优化包括:自动微分、常量折叠、公共子表达式消除;编译器后端与硬件相关,其转换和优化包括:代码指令生成和编译、算子选择、内存分配、内存复用等。

二、Session是干啥的?

2.1 Session定义

       tf.Session代表用户程序和C++运行时之间的连接。一个Session类对象session可以用来访问本机计算设备,也可访问TF分布式运行时环境中的远程设备。session也能缓存tf.Graph信息,使得相同计算逻辑的多次执行得以高效实现。

       tf.Session的构造方法定义如下:我们来看一下__init__()方法的三个参数:

2.2 Session.run()

tf.Session.run()实际是调用tf.BaseSession.run()方法,其函数签名如下:

       run()方法的参数说明如下:当Session指定fetches后,根据要获取的结果决定tf.Graph实际执行的subgraph(并非整个tf.Graph都要执行)。执行静态图还有三个要点:首先我们看一下和用户直接打交道的前端Session,具体分为普通Session和交互式InteractiveSession。前者全称为tf.Session,需要在启动之前先构建完整的计算图;后者全称为tf.InteractiveSession,它是先构建一个session,然后再定义各种操作,适用于shell和IPython等交互式环境。这两个类均继承自BaseSession,这个基类实现了整个生命周期的所有会话逻辑(相关代码在tensorflow/python/client/session.py中)。前端Session类的继承关系如下图:

       TensorFlow后端会根据前端tf.Session(target='', graph=None, config=None)创建时指定的target来创建不同的后端Session。target是要连接的TF后端执行引擎,默认为空字符串。后端Session的创建采用抽象工厂模式,如果为空字符串,则创建本地DirectionSession;如果是grpc://开头的URL串,则创建分布式GrpcSession。

三、静态图执行过程

       为便于大家理解,我们先给出粗粒度的静态图执行原理如下:静态图的实际执行过程要比上文描述的复杂得多。由于本篇的初衷不是做源码的完整剖析,因此我们仅就Client向Master的处理过程做详细说明,旨在让读者亲身体会一下交互过程的复杂性。Client创建GrpcSession,控制Client会话的生命周期;Master运行时被MasterSession控制。GrpcSession通过抽象工厂模式得到,首先得到工厂类GrpcSessionFactory的对象,并用SessionFactory句柄factory存储。然后通过factory的多态方法生成GrpcSession,如果target为grpc://的话。Master本质上是一个Server,每个Server均有一个MasterService和一个WorkerService。Client通过GrpcSession调用Master节点的MasterService,这个过程需借助MasterInterface才可完成。MasterInterface用来和MasterService进行通信,它有两种不同的场景实现:如果读者想对上述过程做更为深入的了解,可以参考关键类的源码。

四、总结

       作为Dive into TensorFlow系列第一讲,本文由浅入深、系统讲解了静态图及其运行原理,以及支撑这些功能的架构设计与部分源码解析。回到文章开头提到的用户读懂全文能有什么收益?(尝试提几点)

       参考文献:

Graphs and Sessions:github.com/tensorflow/d... 《机器学习系统:设计与实现》:openmlsys.github.io/cha... 前后端连接的桥梁Session:likecs.com/show-... TensorFlow v1..5源码:github.com/tensorflow/t... TensorFlow Architecture:github.com/tensorflow/d... TensorFlow分布式环境Session:cnblogs.com/rossiXYZ/p...

TensorFlow 源码大坑(2) Session

       深入探讨TensorFlow源码中的Session机制,揭示其运行机制和复杂性。从Python和C++两端的Session API入手,解析其调用栈,解析内部工作流程。Python端的tf.Session().run()方法,通过初始化调用栈,实现计算图的执行。C++端的ClientSession.run()同样展示了Session运行机制,揭示了底层实现细节。对比之下,DirectSession作为Session的基类,展示了如何构建Executor并具体运行计算图,为理解TensorFlow的高效计算逻辑提供了深入视角。

       深入解析Python端tf.Session().run()方法的调用栈,揭示了其如何通过初始化调用栈来执行计算图的全过程。从创建Session到调用run方法,每一次调用都紧锣密鼓地执行一系列操作,确保计算图能够正确运行,这使得理解TensorFlow的执行流程变得清晰。

       同时,C++端的ClientSession.run()方法提供了另一种视角,展示了Session运行机制在底层语言中的实现。通过对比Python和C++端的实现,可以更深入地理解TensorFlow在不同环境下的兼容性和性能优化。

       DirectSession作为Session的基类,展示了如何构建Executor并具体运行计算图。通过分析DirectSession的run方法和构建过程,可以理解TensorFlow在执行计算图时的灵活性和高效性,以及如何通过Executor优化计算流程。

       总之,深入研究TensorFlow源码中的Session机制,不仅能够揭示其复杂性,还能为开发者提供优化计算图执行流程、提升模型训练效率的策略,是理解TensorFlow内核机制的关键。

极简入门TensorFlow C++源码

       前一段时间,我专注在框架开发上,并偶尔协助业务同学优化使用TensorFlow的代码。在观看dmlc/relay、nnvm的代码时,我发现了它们的有趣之处。我也对TensorFlow的Graph IR、PaddlePaddle的Graph IR产生了兴趣,上周五在阅读代码时,无意间听到了一个数据竞赛群讨论框架的底层实现。几位算法大佬提到了看底层源码可能较为繁琐,因为这类代码通常相对容易理解。在与群内伙伴的交流后,我萌生了撰写一篇关于如何阅读TensorFlow或其他框架底层源码的文章。

       选择合适版本的bazel,对于阅读TensorFlow源码至关重要。应使用版本为0..0的bazel来拉取TF2.0代码,因为太高的版本或太低的版本可能影响阅读体验。在安装了合适的bazel版本后,使用clion上的bazel插件进行导入,然后配置编译,导入项目,等待clion编译整个项目。完成编译后,就能愉快地阅读代码,甚至于protobuf生成的文件也能轻松跳转。

       使用c++编译模型是TensorFlow的另一面。尝试使用c++编写模型代码,可以深入理解TensorFlow的底层机制。主要函数包括CreateGraphDef、ConcurrentSteps、ConcurrentSessions等。通过这些函数,可以构建计算图,定义节点、常量变量、操作符等。这为理解TensorFlow的逻辑提供了直观的视角。

       深入分析代码后,可以了解到TensorFlow的GraphDef机制、Square类的实现、注册到特定op的过程、functor的使用以及最终的实现逻辑。这有助于理解TensorFlow的核心原理,并在阅读源码时进行更深入的思考。

       除了阅读源码,还可以通过编写测试用例来增强理解。TensorFlow提供了丰富的测试用例,如在client_session_test.cc中运行测试程序,可以验证代码的正确性。这不仅有助于理解代码,还能提高对TensorFlow框架的掌握程度。

       阅读源码只是理解TensorFlow原理的开始,深入行业论文和请教行业专家是进一步深入学习的关键。网络上关于机器学习系统的资料丰富多样,但缺少系统性的课程。希望官方能够分享更多框架的干货,并期待在学习过程中总结和分享更多资源。阅读源码虽然复杂,但其背后蕴含的原理和逻辑十分有趣。

更多内容请点击【综合】专栏