Treevalue(0x01)——功能概述
TreeValue——一个通用树状数据结构与函数计算库
Treevalue v1.0.0版本已经于2021年10月24日正式发布,欢迎下载体验:opendilab / treevalue。
这算是treevalue的第一个正式实用化版本,本文将会对其主要功能和特性进行一个概述。
一个直观地展示
设想这样一个实际的应用场景,我们需要使用numpy对机器学习中的一批样本进行预处理,并组装成一个训练用的mini-batch。一个数据样本的格式如下面的代码所示,即函数 get_data 的返回值:
import numpy as np
T, B = 3, 4
def get_data():
return {
'a': np.random.random(size=(T, 8)),
'b': np.random.random(size=(6,)),
'c': {
'd': np.random.randint(0, 10, size=(1,))
}
}
如果使用最常见的写法,大概会是这样的
# without_treevalue.py
import numpy as np
T, B = 3, 4
def without_treevalue(batch_):
mean_b_list = []
even_index_a_list = []
for i in range(len(batch_)):
for k, v in batch_[i].items():
if k == 'a':
v = v.astype(np.float32)
even_index_a_list.append(v[::2])
elif k == 'b':
v = v.astype(np.float32)
transformed_v = np.power(v, 2) + 1.0
mean_b_list.append(transformed_v.mean())
elif k == 'c':
for k1, v1 in v.items():
if k1 == 'd':
v1 = v1.astype(np.float32)
else:
print('ignore keys: {}'.format(k1))
else:
print('ignore keys: {}'.format(k))
for i in range(len(batch_)):
for k in batch_[i].keys():
if k == 'd':
batch_[i][k]['noise'] = np.random.random(size=(3, 4, 5))
mean_b = sum(mean_b_list) / len(mean_b_list)
even_index_a = np.stack(even_index_a_list, axis=0)
return batch_, mean_b, even_index_a
而当我们有了treevalue库之后,完全一致的功能可以被这样简短的代码实现
# with_treevalue.py
import numpy as np
from treevalue import FastTreeValue
T, B = 3, 4
power = FastTreeValue.func()(np.power)
stack = FastTreeValue.func(subside=True)(np.stack)
split = FastTreeValue.func(rise=True)(np.split)
def with_treevalue(batch_):
batch_ = [FastTreeValue(b) for b in batch_]
batch_ = stack(batch_)
batch_ = batch_.astype(np.float32)
batch_.b = power(batch_.b, 2) + 1.0
batch_.c.noise = np.random.random(size=(B, 3, 4, 5))
mean_b = batch_.b.mean()
even_index_a = batch_.a[:, ::2]
batch_ = split(batch_, indices_or_sections=B, axis=0)
return batch_, mean_b, even_index_a
可以看到,实现一段同样的基于树结构的业务逻辑,有了treevalue库的辅助后代码变得极为简短和清晰,也更加易于维护。
这正是treevalue的最大亮点所在,接下来的章节中将会对其主要功能和特性进行概述,以便读者对这个库有一个整体的了解和认识。
树结构及其基本操作
在treevalue库中,我们提供一种核心数据结构—— TreeValue 类。该类为整个treevalue的核心特性,后续的一系列操作都是围绕 TreeValue 类所展开的。
首先是 TreeValue 对象的构造(使用的是增强版子类 FastTreeValue ,关于 TreeValue 类与 FastTreeValue 类的区别可以参考文档,本文不作展开),只需要将dict格式的数据作为唯一的构造函数参数传入即可完成TreeValue的构造
from treevalue import FastTreeValue
t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
# <FastTreeValue 0x7f135a5ada30>
# ├── a --> 1
# ├── b --> 2
# └── x --> <FastTreeValue 0x7f135a5ad970>
# ├── c --> 3
# └── d --> 4
不仅如此, TreeValue 类还提供了树状结构的几种基本操作接口供使用
from treevalue import FastTreeValue
t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
## get value/node
t.a # 1
t.x # <FastTreeValue 0x7f135a5ad970>
# ├── c --> 3
# └── d --> 4
t.x.d # 4
## set value/node
t.x.d = 35
# t after t.x.d = 35
# <FastTreeValue 0x7f135a5ada30>
# ├── a --> 1
# ├── b --> 2
# └── x --> <FastTreeValue 0x7f135a5ad970>
# ├── c --> 3
# └── d --> 35
## delete value/node
del t.b
# t after del t.b
# <FastTreeValue 0x7f135a5ada30>
# ├── a --> 1
# └── x --> <FastTreeValue 0x7f135a5ad970>
# ├── c --> 3
# └── d --> 35
## contains key or not
'a' in t # True
'd' in t # False
'd' in t.x # True
## size of node
len(t) # 2, 'a' and 'x'
len(t.x) # 2, 'c' and 'd'
## iterate node
for k, v in t.x:
print(k, '-->', v)
# c --> 3
# d --> 35
以上是 TreeValue 类的几种常见基本操作,支持了最基本的增删查改等。
树的可视化
当一个 TreeValue 对象被构造出来后,我们如何比较直观地去观察其整体结构呢?有两种方式可以对 TreeValue 进行可视化:
- 通过
print进行快速文字打印 - 通过
treevalue graph命令行工具进行图像导出
实际上对于第一种情况,在上一节中已经有了展示,在此展示一个更加复杂的案例
# test_simple.py
import torch
from treevalue import FastTreeValue
t = FastTreeValue({
'a': torch.randn(2, 3), # objects with multiple lines
'b': torch.randn(3, 1, 2),
'x': {
'c': torch.randn(3, 4),
}
})
t.x.d = t.x # nested pointer
print(t)
输出结果如下,可以看到诸如 torch.Tensor 这样多行的对象也一样可以被有序地排版输出,且对于存在嵌套引用的情况,输出时也可以被准确地识别出来,避免无限循环打印
<FastTreeValue 0x7f642057bd00>
├── a --> tensor([[ 0.1050, -1.5681, -0.2849],
│ [-0.9415, 0.2376, 0.7509]])
├── b --> tensor([[[ 0.6496, -1.3547]],
│
│ [[ 1.2426, -0.2171]],
│
│ [[-0.7168, -1.4415]]])
└── x --> <FastTreeValue 0x7f642057bd30>
├── c --> tensor([[-0.6518, 0.4035, 1.0721, -0.6657],
│ [ 0.0252, 0.4356, 0.1284, -0.3290],
│ [-0.6725, 0.2923, 0.0048, 0.0704]])
└── d --> <FastTreeValue 0x7f642057bd30>
(The same address as <root>.x)
除了基于文本的可视化外,我们还提供了命令行工具以进行图像导出。例如上面的代码,我们可以用如下的命令行导出图像
treevalue graph -t 'test_simple.t' -o 'test_graph.png'

此外,对于更复杂的情况,例如这样的一份源代码
# test_main.py
import numpy as np
from treevalue import FastTreeValue
tree_0 = FastTreeValue({
'a': [4, 3, 2, 1],
'b': np.array([[5, 6], [7, 8]]),
'x': {
'c': np.array([[5, 7], [8, 6]]),
'd': {'a', 'b', 'c'},
'e': np.array([[1, 2], [3, 4]])
},
})
tree_1 = FastTreeValue({
'aa': tree_0.a,
'bb': np.array([[5, 6], [7, 8]]),
'xx': {
'cc': tree_0.x.c,
'dd': tree_0.x.d,
'ee': np.array([[1, 2], [3, 4]])
},
})
tree_2 = FastTreeValue({'a': tree_0, 'b': tree_1, 'c': [1, 2], 'd': tree_1.xx})
可以通过以下的命令行导出为图像,不难发现对于共用节点和共用对象的情况也都进行了准确地体现(如需进一步了解,可以执行 treevalue graph -h 查看帮助信息)
treevalue graph -t 'test_main.tree_*' -o 'test_graph.png' -d numpy.ndarray -d list -d dict

以上是对于 TreeValue 对象的两种可视化方法。
函数的树化
在treevalue中,我们可以快速地将函数进行装饰,使之可以支持 TreeValue 对象作为参数进行运算。例如下面的例子
# test_gcd.py
from treevalue import FastTreeValue, func_treelize
@func_treelize(return_type=FastTreeValue)
def gcd(a, b): # GCD calculation
while True:
r = a % b
a, b = b, r
if r == 0:
break
return a
if __name__ == '__main__':
t1 = FastTreeValue({'a': 2, 'b': 30, 'x': {'c': 4, 'd': 9}})
t2 = FastTreeValue({'a': 4, 'b': 48, 'x': {'c': 6, 'd': 54}})
print("Result of gcd(12, 9):", gcd(12, 9))
print("Result of gcd(t1, t2):")
print(gcd(t1, t2))
将整数之间的最大公因数进行了装饰后,可以形成兼容 TreeValue 对象的函数,且不会影响普通对象的运算结果,因此上述代码的输出结果如下所示
Result of gcd(12, 9): 3
Result of gcd(t1, t2):
<FastTreeValue 0x7f53fa67ff10>
├── a --> 2
├── b --> 6
└── x --> <FastTreeValue 0x7f53fa67ff40>
├── c --> 2
└── d --> 9
树结构的运算
除了 TreeValue 自带的一系列基本操作之外,treevalue库还提供了一些常用的树结构运算函数。例如如下的四种:
- map——值映射运算
- reduce——值归纳运算
- subside——顶层结构下沉运算
- rise——值结构提取上浮运算
值映射运算(map)
TreeValue 对象的值映射运算和列表类型的map运算类似,会产生一个同结构且值为映射值的新 TreeValue 对象,例如下面的案例
from treevalue import FastTreeValue
t1 = FastTreeValue({'a': 2, 'b': 30, 'x': {'c': 4, 'd': 9}})
t2 = t1.map(lambda x: x * 2 + 1)
t1 和 t2 的图像如下

值归纳运算(reduce)
TreeValue 对象的值归纳运算和 functools.reduce 函数的功能类似,可以将树结构以子树为单位进行归纳,最终计算出一个结果来,例如下面的案例
from treevalue import FastTreeValue
t1 = FastTreeValue({'a': 2, 'b': 30, 'x': {'c': 4, 'd': 9}})
# sum of all the values in t1
t1.reduce(lambda **kws: sum(kws.values())) # 45
可以快捷的实现整棵树的求和运算。
顶层结构下沉运算(subside)
TreeValue 还可以支持将其上层结构进行解析后,下沉到节点值上,形成一棵新的树,例如下面的案例
from treevalue import FastTreeValue
dt = {
'i1': FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3}}),
'i2': (
FastTreeValue({'a': 7, 'b': 4, 'x': {'c': 6}}),
FastTreeValue({'a': 11, 'b': 9, 'x': {'c': -3}}),
),
}
t = FastTreeValue.subside(dt)
下沉后产生的树 t 的图像为

值结构提取上浮运算(rise)
上浮运算(rise)为下沉运算的逆运算,可以从值节点中提取共同结构至 TreeValue 对象外,例如如下的案例
from treevalue import FastTreeValue, raw
t = FastTreeValue({
'a': raw({'i1': 1, 'i2': (7, 11)}),
'b': raw({'i1': 2, 'i2': (4, 9)}),
'x': {
'c': raw({'i1': 3, 'i2': (6, -3)}),
}
})
dt = t.rise()
dt_i1 = dt['i1']
dt_i2_0, dt_i2_1 = dt['i2']
对象 dt 是一个字典类型的对象,包含 i1 和 i2 两个键,其中 i1 为一个 TreeValue 对象, i2 为一个长度为2,由 TreeValue 对象构成的元组。因此 dt_i1 、 dt_i2_0 和 dt_i2_1 的图像为

后续预告
本文作为一个对于treevalue现有主要功能的一个概述,受限于篇幅暂时做不到深入全面的讲解内部原理和机制。因此后续会考虑继续出包括但不限于以下的内容:
- treevalue的整体体系结构
func_treelize树化函数的原理与机制- treevalue的一些神奇的用法与黑科技
- treevalue的优化历程与经验
- treevalue的具体实战案例
敬请期待,同时欢迎了解其他OpenDILab的开源项目:https://github.com/opendilab。
Treevalue(0x01)——功能概述的更多相关文章
- Power BI官方视频(1) Power BI Desktop 7月份更新功能概述
2016年7月,Power BI Desktop进行了一些功能更新,提高整体的用户体验.同时也有一些新的和令人兴奋的功能.看看大概介绍,更新功能要点: 本文原文地址:Power BI官方视频(1) P ...
- osgearth各个例子功能概述
osgearth各个例子功能概述 转自:http://blog.csdn.net/wl198302/article/details/21177309 最近在学习osgearth,对其还不是很理解,有些 ...
- SAP Business One SAP B1功能概述
SAP Business One SAP B1功能概述 SAP B One配有易于使用的软件界面,是一款全面的,多功能的业务管理解决方案,贵企业可以将其用作主要的企业资源(ERP)应用程序. 该解决方 ...
- Android(java)学习笔记102:Map集合功能概述
下面通过代码引入Map集合:如下 package cn.itcast_01; import java.util.HashMap; import java.util.Map; /* * 作为学生来说,是 ...
- Java基础知识强化之集合框架笔记51:Map集合之Map集合的功能概述与测试
1. Map集合的功能概述 (1)添加功能 V put(K key,V value):添加元素.这个其实还有另一个功能?先不告诉你,等会讲 如果键是第一次存储,就直接存储元素,返回null 如果键不是 ...
- Java基础知识强化之集合框架笔记16:List集合的特有功能概述和测试
1. List集合的特有功能概述: (1)添加功能: void add(int index, Object element):在指定位置添加元素 (2)获取功能: Object get(int ind ...
- Java基础知识强化之集合框架笔记03:Collection集合的功能概述
1. Collection功能概述:Collection是集合的顶层接口,它子体系有重复的,有唯一性,有有序的,无序的. (1)添加功能 boolean add(Object obj):添加一个元素 ...
- ABBYY PDF Transformer+功能概述
ABBYY PDF Transformer+是一个新的.全面的巧妙解决PDF文档的工具,它将泰比的光学字符识别(OCR)技术和Adobe®PDF技术完美结合,以确保实现便捷地处理任何类型的PDF文件, ...
- MicroRNA in Control of Gene Expression: An Overview of Nuclear Functions 微RNA控制基因表达:核功能概述
MicroRNA in Control of Gene Expression:An Overview of Nuclear Functions微RNA控制基因表达:核功能概述 抽象:小的非编码RNA( ...
随机推荐
- type switch使用
type switchs用法 这里存在一个未知类型变量的内省操作(introspection operation),就是x.(type),其中x是interface{}类型
- 树莓派修改默认pi帐号亲测有效
# 树莓派修改默认pi帐号亲测有效### 1.我的树莓派机型:3B+,系统:Raspbian桌面标准版,连接的屏幕:电视机..###2.打开树莓派LX终端,快捷键:Ctrl+Alt+t ###3.输入 ...
- python matplotlib.pyplot 散点图详解(1)
python matplotlib.pyplot散点图详解(1) 一.创建散点图 可以用scatter函数创建散点图 并使用show函数显示散点图 代码如下: import matplotlib.py ...
- POJ 2509 Peter's smokes(Peter的香烟)
POJ 2509 Peter的香烟 描述 Peter抽烟.他抽烟一个个地抽着烟头.从 k (k>1) 个烟头中,他可以抽一根新烟.彼得可以抽几支烟? 输入 输入是一系列行.每行包含两个给出n和k ...
- 【简单数据结构】二叉树的建立和递归遍历--洛谷 P1305
题目描述 输入一串二叉树,用遍历前序打出. 输入格式 第一行为二叉树的节点数n.(n \leq 26n≤26) 后面n行,每一个字母为节点,后两个字母分别为其左右儿子. 空节点用*表示 输出格式 前序 ...
- js 之k个一组翻转链表
题目描述 将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样你不能更改节点中的值,只能更改节点本身.要求空间复杂度 \ O ...
- java循环结构、数组
数组 数组是是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理. 数组本身是引用数据类型,既可以存储基本数据类型,也可以存储引用数据类型.它的元素相当于 ...
- UML类图及其JAVA的代码实现
推荐 : https://my.oschina.net/u/3635618/blog/3165129 http://www.uml.org.cn/oobject/201104212.asp
- Docker系列(9)- 常用其他命令(2) | 进入容器和拷贝的命令
进入当前正在运行的容器 #我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置#方法一 命令docker exec -it 容器ID bashShell#测试[root@localhost ...
- 华为云计算IE面试笔记-FusionCompute上的虚拟机A和虚拟机B不能正常通信,请描述可能的故障点和排除方法(分析虚拟机A和虚拟机B不通)
*快速定位故障点:(考到) ARP:同一二层内可以通过ARP -a命令查询到要访问的主机IP(ARP表项中记录了同一二层中的IP和MAC的对应关系),若查询不到,说明二层出现问题(Vlan 间不通)或 ...