treevalue——Master Nested Data Like Tensor
首先,请和我一起高呼——“treevalue——通用树形结构建模工具 + 极简树形结构编程模型”。
咳咳,好久没更新了,这一次是真的好久不见,甚是想念。在之前的三期中,关于 treevalue
的核心特性等内容已经基本完成了讲述。因此本篇作为该系列的终章,将尝试用更高一层的视角来分析 treevalue
,以求进一步了解其核心思想与应用模式,并通过干货数据与实例展示来展现其真实能力。
闲话少叙,让我们开始吧!如果还没了解过 treevalue
的小伙伴们可以先去读一下之前的几篇文章:
整体设计
概念与架构
想要完整地了解 treevalue
,首先还是需要从整体架构上来看看,如下图所示。
(treevalue的整体架构)
显而易见的一点, treevalue
是基于Python构建的,并且处于运算性能上的考虑,因此也大量采用了Cython来实现,该工具可以用一种介于Python和C/C++之间的语法进行编码,并以C/C++的形式编译为静态库,通过绕开一系列不必要的动态机制等方式来实现明显的加速。
在 treevalue
中,最底层的为 TreeStorage
,为数据层,主要对树状数据结构进行管理,并对上层提供最基本的接口。建立在之上的 TreeValue
为最关键的一个类,基于数据层进行了基本的封装,能实现 treevalue
的基本特性且具备进一步扩展的能力。树化(treelize)在之前的几篇文章中有过介绍,其作用在于将现有库的函数和类进行树化的扩展,使 treevalue
的特性可以被快速应用至现有工具上。工具部分(utilities)即为基于 TreeValue
构建的一些简单工具,支持了基本的树操作、函数式运算等功能。另一个极为重要的部分即为 FastTreeValue
类,其为 TreeValue
的子类,包含了大部分的运算符,并可以实现“装载即用”,只需要将现有的对象装入FastTreeValue
即可批量访问其属性、批量调用其方法,因此 FastTreeValue
被最为广泛的使用。这里需要注意的是, treevalue
并未针对任何一个特定的现有库进行特殊化设计,而是通过泛用型设计,让诸如PyTorch、Numpy、Tensorflow在内的几乎全部接口均可以被快速扩展到树运算上。
总的来说,基于 treevalue
,可以将现有轮子中的函数与类扩展为支持树状运算的新形态,并可以让编程者基于这一扩展进行更加方便快捷的代码构建。
设计定位
在前面几篇该系列的文章里,我们都加上了“强化学习(Reinforcement Learning)”的标签,也是因此,此文才会被推送到关注了这一话题的用户手里。可是你们大概已经发现,无论是之前的三篇文章,还是我们的源码仓库,都并没有深度强化学习相关的内容,甚至在源代码中看不到 numpy
或 torch
等常见AI相关库的存在。想必各位读者也从之前的文章发出后便早已疑惑多时了。因此在这里我们来回答一个重要的问题—— treevalue
的设计定位是什么?
其实仔细琢磨的话,答案也已经很明显了—— treevalue
从设计之初就是一款具备充分泛用型,且易用性为主运行性能为辅的树数据结构计算框架。之前各个文章乃至代码中未大量涉及具体的深度强化学习内容也正是这个原因。在Treevalue(0x02)——函数树化详细解析(上篇)中介绍的 func_treelize
特性也是可以针对任意函数进行使用的,因此即便不是 torch
这样的经典的库,换上其他的库与其他的类、方法,也同样可以使用treevalue
,且使用体验与原本的库基本一致,极为友好。甚至于深度强化学习以外的任意领域,只要有基于树结构的运算的地方, treevalue
就有它的用武之地——这也正是它设计上的核心理念,与真正的优势所在。
与同类产品的对比
基于上述的介绍,读者们可能会担心一个易用性、泛用性为主的库,会不会在其他上,尤其是在深度强化学习程序的特性支持与运行性能上存在劣势。这样的顾虑其实很正常,因为在大部分情况下,软件的泛用性和性能都是不容易做到兼顾的。但是 treevalue
是否存在这样的问题呢?因此本节将会通过与同类或相近产品的对比分析,来对这一问题进行回答。
同类或相近产品介绍
在 treevalue
开发与测试的阶段,我们发现其实在现有的其他库中,也有类似的树状运算支持。其中比较具有典型意义的有以下四个:
- dm-tree,DeepMind团队开发的轻量级树状运算库。
- Tianshou-Batch,清华大学机器学习组开发,基于PyTorch的深度强化学习库,其中Batch为重点设计的一个关键组件。
- jax-libtree,谷歌团队开发的机器学习库,其中libtree为内部的一个轻量级树运算封装库。
- torchbeast-nest,Meta研究院(原facebook研究院)开发,基于PyTorch的深度强化学习框架,其中nest为内部的一个轻量级树运算封装库。
特性对比
基于上面提到的四款同类产品及 treevalue
,所开源的代码及提供的文档,可以得出以下的分析。
同类产品 | 重量级 | 泛用性 | 函数式 | 结构运算 | 自建结构 | 函数扩展 | 自扩展 |
---|---|---|---|---|---|---|---|
dm-tree | 轻量级 | √ | √ | × | × | × | × |
Tianshou-Batch | 中轻量级 | × | × | × | √ | × | × |
jax-libtree | 轻量级 | √ | √ | √ | × | × | × |
torchbeast-nest | 轻量级 | √ | √ | × | × | √ | × |
treevalue | 中量级 | √ | √ | √ | √ | √ | √ |
具体来说:
- dm-tree为基于C++实现的独立轻量级库,不针对特定的框架,且支持简单的函数式运算。
- tianshou-Batch为中轻量级库,自建了一套针对PyTorch的树数据结构,实现了基本的增删查改功能,并且实现了包括stack、split在内的少量运算操作。
- jax-libtree为Google Jax库中的子模块,不针对特定框架,支持简单的函数式运算,还支持了诸如transpose这样的树结构运算。
- torchbeast-nest为Meta torchbeast中的树结构子模块,不针对特定框架,支持简单的函数式运算,此外还支持简单的二元函数扩展运算能力。
而相比之下,treevalue
为一款泛用型中量级库,且支持主要的函数式运算。其实现原理为自建树状数据结构,并基于这一结构展开运算。不仅如此,还支持了比jax-libtree更加丰富的结构运算(subside与支持自动检测结构的rise),也支持了比torchbeast-nest更灵活的函数扩展能力(func_treelize)。而treevalue
最为强大的地方体现在treetensor中,只需要对部分torch.Tensor
的方法进行特别支持后,剩下的全部方法均可在现有框架上实现,并保持和原有API一样的使用方式。
这一点,意味着对于基于 treevalue
的开发者而言,不再需要大规模逐个进行封装迁移,只需要针对个别较特殊的API进行特别实现,其他的可以直接批量快速映射,直接做到无一遗漏。实际上,对于兼容库的开发而言,往往实现了90%,甚至与99%的接口,都可能对实际使用带来较多的限制,而基于treevalue
开发的应用而言,则在原理上便不存在这一问题,接口的扩展可以一步到位。而对于使用者而言,兼容库的使用体验将和原有库高度一致,原有的运算性质不会改变,且进一步支持了树状运算,而一步到位的兼容更是让使用者不会被不全的API所限制,使用体验极佳,甚至于可以将现有代码以极小规模的修改便实现从原有库向兼容库的迁移,很容易确保正常运行,并可以进一步简化代码实现。
性能对比
上文中提到, treevalue
是其中唯一的一款中量级库,这意味着从实现的角度来看,其需要为了支持高度的泛用性和易用性,而考虑更多的情况,设立更多的处理机制。因此,理论上 treevalue
会在性能上存在一定的劣势。然而事实真的如理论所言吗?让我们来看看接下来的性能分析数据。
在本次性能对比中,我们将根据同类产品的特点,将实验分为两组:
- 数据结构组——tianshou Batch和treevalue,比较对象为split(将单个Tensor进行拆分)、stack(将多个Tensor进行拼接)运算的性能
- 泛用运算组——dm-tree、jax-libtree、torchbeast-nest和treevalue,比较对象为flatten(将树结构展开为可逆的列表结构)、mapping(简单的函数式映射运算)运算的性能
数据结构组的性能测试结果如下所示,不难发现treevalue
在张量运算的性能上具有明显优势。
(treevalue和tianshou Batch在torch.split操作上的性能对比,treevalue具有明显的优势)
(treevalue和tianshou Batch在torch.stack操作上的性能对比,treevalue具有明显的优势)
泛用运算组的性能测试结果如下图所示,其中dm-tree为其中最轻量级的库,却意外地拥有最低的性能;而jax-libtree和torchbeast-nest相比之下拥有不错的性能。但是,作为中量级库且包含大量易用性设计的treevalue
,仍然在各种规模的数据上拥有性能优势——在小规模数据上优势极为明显,即便在大规模数据上依然可以较之jax-libtree保持微弱优势,且较之torchbeast-nest保持大比例的优势。
(treevalue、dm-tree、jax-libtree、torchbeast-nest在flatten运算上的性能对比,treevalue整体处于优势)
(treevalue、dm-tree、jax-libtree、torchbeast-nest在mapping运算上的性能对比,treevalue整体处于优势)
不仅如此,我们还针对其他的各类基础操作于运算进行了性能测试,更多的测试结果信息参见项目README.md。
经过一系列的测试,结果表明性能问题并未出现,甚至于相较于同类产品仍有性能优势。这一点对于中量级设计的库而言是极为难得的,这意味着无论从性能还是从使用体验来说,treevalue
均具备全方位的优势。
案例对比
在上文中,我们在与同类产品的的对比中,展现了 treevalue
强大的泛用性与易用性,以及堪称优秀的运算性能。而实际上要想更具说服力地展现这一点,还是需要一些更加具体的例子。
首先是官方文档中的两组例子,分别用于Numpy和Scikit-Learn:
- Apply Into Numpy,这组例子展现了在实现同样涉及树数据结构的情况下,使用
FastTreeValue
的代码极为明显地短于原有实现,且简洁清晰程度远超以往。 - Apply Into Scikit-Learn,该组例子展现了基于原有的接口,通过极简的装饰扩展即可将PCA运算应用到整棵树上,得出整棵树的解,全程高度精简易懂。
此外,我们还准备了一个treevalue
用于具体DRL项目的例子,这次我们选择了在深度强化学习领域最复杂的项目——AlphaStar中的相关数据处理函数collate_fn
,这个函数的作用是在每个训练iteration之前对数据进行堆叠、填充和预处理。原始的代码充斥着大量的for循环和if-else分支控制,而通过使用treevalue
,我们可以将上述所有操作完全用并行操作API重写,具体来说,两个版本的代码度量分析如下表所示:
这表明, treevalue
在复杂项目上的优势将更加显著,具体表现为代码行数缩减到1/3,逻辑复杂度大幅降低,可维护性明显提高——以及由此带来的编码用时大幅缩减。此外,在性能测试中,treevalue
版代码相较于原始代码也并无劣势。至此, treevalue
的各项能力已经得到了充分的验证。
展望
treevalue
的各项能力,在上文中已经进行了充分的论述。因此,本节将采用开放式问题的方式,抛出一系列问题,也作为展望。欢迎读者一同参与讨论,以及如有更进一步的脑洞,也欢迎留言~~
问题1:你认为, treevalue
仅仅只是一个库?一组操作工具?还是一整套运算模型?
问题2: treevalue
运算模型的核心是什么?此处核心指的是,基于该核心可以直接或间接衍生出几乎全部现有特性。
问题3:在之前的文章中,已经详细描述了函数的树化扩展(treelize)机制,效果为将普通函数扩展为支持树运算的函数。除此之外,是否还有其他类似的可扩展对象?是否有可以基于函数树化的上位可扩展对象?
问题4:如果需要对现有的数据模型类(例如torch.Tensor、np.ndarray等)进行树化扩展,需要注意哪些问题?工厂类(工厂模式构建的类)呢?工具类(集成静态工具的类,多见于Java)呢?对模块(module)的扩展呢?上述的各种扩展机制是否可以归纳为另一种统一的运算模型?
问题5:treevalue相较于同类产品的性能优势虽然普遍存在,但依然没有做到全方位拉开差距。有哪些可能的优化点?其中哪些是可以针对具体应用情况作针对性优化的?
问题6:如何通过扩展让treevalue支持任意类型的数据容器(包括list、tuple,甚至自建数据模型)?眼下的主要障碍在哪里?是在技术上还是运算模型上?
问题7:你还能想到其他的 treevalue
+ 机器学习的应用吗?图神经网络数据结构的表示是否可以实现?
treevalue——Master Nested Data Like Tensor的更多相关文章
- Vue开发警告[Vue warn]: Avoid replacing instance root $data. Use nested data properties instead.
Avoid replacing instance root $data. Use nested data properties instead. 翻译 避免替换实例根$data.请改用嵌套数据属性 错 ...
- ElasticStack系列之九 & master、data 和 client 节点
在生产环境下,如果不修改elasticsearch节点的角色信息,在高数据量,高并发的场景下集群容易出现脑裂等问题. 默认情况下,elasticsearch 集群中每个节点都有成为主节点的资格,也都存 ...
- [PyTorch 学习笔记] 1.2 Tensor(张量)介绍
本章代码: https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/tensor_introduce1.py https: ...
- ExtJS4笔记 Data
The data package is what loads and saves all of the data in your application and consists of 41 clas ...
- Working with Data » 使用Visual Studio开发ASP.NET Core MVC and Entity Framework Core初学者教程
原文地址:https://docs.asp.net/en/latest/data/ef-mvc/intro.html The Contoso University sample web applica ...
- ZooKeeper场景实践:(6)集群监控和Master选举
1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...
- jquery data方法取值与js attr取值的区别
<a data-v="3"></a> jquery data方法的运行机制: 第一次查找dom,使用attributes获取到dom节点值,并将其值存到缓存 ...
- spi master接口的fpga实现
前言 当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机. spi:serial peripheral interface 串行 ...
- TensorFlow使用基础-Tensor
使用 TensorFlow 之前你需要了解关于 TensorFlow 的以下基础知识 :• 使用图 (graphs) 来表示计算 .• 在会话 ( Session ) 中执行图 .• 使用张量 (te ...
随机推荐
- Python 安装第三方模块时 报Retrying(Retry(total=4, connect=None, read=None, redirect=None, status=None))...[WinError 10061]由于目标计算机积极拒绝,无法连接 错误
今日在安装ddt模块时(Windows系统),cmd报了一个以前从未见过的错误,如下图所示: 经百度,知是镜像源的问题,将安装命令改成如下命令: pip install ddt -i https:// ...
- django 字段默认值
default 表示在页面中默认选中状态的值 页面为 来自为知笔记(Wiz)
- 通过USB和wifi连接真机&编写第一个脚本
一.通过USB和wifi连接真机 1. 数据线连接手机并允许调试 cmd命令行执行:adb devices (能查看到设备就可以进行编写自动化脚本步骤了,如果在USB接触不良的情况下,可以执行下面步骤 ...
- 物理机异常断电,linux虚拟机系统磁盘mount失败,导致无法启动; kubectl 连接失败
虚拟机 CentOS 7 挂载文件系统失败 上周五下班前没有关闭虚拟机和物理机, 今天周一开了虚拟机之后,发现操作系统启动失败. 原因跟 这篇文章描述的一模一样. 解决操作系统的文件系统挂载的问题之后 ...
- PyCharm - 关联mysql失败 - Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.
时区错误,MySQL默认的时区是UTC时区,比北京时间晚8个小时. 所以要修改mysql的时长 在mysql的命令模式下,输入: set global time_zone='+8:00'; 再次连接成 ...
- Eclipse配置Maven3.5
原文: https://www.toutiao.com/i6494558327622599181/ 配置Maven 首先保证Java环境是有的(Maven 3.1以上 要求 JDK 1.6 或以上版本 ...
- JS调用堆栈
调用栈 JavaScript 是一门单线程的语言,这意味着它只有一个调用栈,因此,它同一时间只能做一件事.如果我们运行到一个函数,它就会将其放置到栈顶.当从这个函数返回的时候,就会将这个函数从栈顶弹出 ...
- conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
conda : 无法将"conda"项识别为 cmdlet.函数.脚本文件或可运行程序的名称.请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次. 解决办法: 没有添加系 ...
- java实现excel表格导入数据库表
导入excel就是一个上传excel文件,然后获取excel文件数据,然后处理数据并插入到数据库的过程 一.上传excel 前端jsp页面,我的是index.jsp 在页面中我自己加入了一个下载上传文 ...
- 【记录一个问题】android下的ucontext协程,因为使用栈上的对象,导致cv::Mat被莫名析构
工作的流程是这样:某个协程在栈上创建task对象,在task对象内有需要返回的cv::Mat. 然后把task放到另一个线程上去执行,然后切换到别的协程,等到工作线程执行完task后,再唤醒协程. 这 ...