Comparison Between TreeValue and Tianshou Batch¶
In this section, we will take a look at the feature and performance of the Tianshou Batch library, which is developed by Tsinghua Machine Learning Group.
Before starting the comparison, let us define some thing.
[1]:
import torch
_TREE_DATA_1 = {'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}
_TREE_DATA_2 = {
'a': torch.randn(2, 3),
'x': {
'c': torch.randn(3, 4)
},
}
_TREE_DATA_3 = {
'obs': torch.randn(4, 84, 84),
'action': torch.randint(0, 6, size=(1,)),
'reward': torch.rand(1),
}
Read and Write Operation¶
Reading and writing are the two most common operations in the tree data structure based on the data model (TreeValue and Tianshou Batch both belong to this type), so this section will compare the reading and writing performance of these two libraries.
TreeValue’s Get and Set¶
[2]:
from treevalue import FastTreeValue
t = FastTreeValue(_TREE_DATA_2)
/tmp/tmp4q2ykbbk/bd171e47eddd5b95747dbb64747e18068f6b3274/treevalue/tree/integration/torch.py:21: FutureWarning: `torch.utils._pytree._register_pytree_node` is deprecated. Please use `torch.utils._pytree.register_pytree_node` instead.
register_for_torch(TreeValue)
/tmp/tmp4q2ykbbk/bd171e47eddd5b95747dbb64747e18068f6b3274/treevalue/tree/integration/torch.py:22: FutureWarning: `torch.utils._pytree._register_pytree_node` is deprecated. Please use `torch.utils._pytree.register_pytree_node` instead.
register_for_torch(FastTreeValue)
[3]:
t
[3]:
[4]:
t.a
[4]:
tensor([[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]])
[5]:
%timeit t.a
45.8 ns ± 0.0131 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
[6]:
new_value = torch.randn(2, 3)
t.a = new_value
t
[6]:
[7]:
%timeit t.a = new_value
50.5 ns ± 1.32 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Tianshou Batch’s Get and Set¶
[8]:
from tianshou.data import Batch
b = Batch(**_TREE_DATA_2)
[9]:
b
[9]:
Batch(
a: tensor([[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]]),
x: Batch(
c: tensor([[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]]),
),
)
[10]:
b.a
[10]:
tensor([[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]])
[11]:
%timeit b.a
40.8 ns ± 0.299 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
[12]:
new_value = torch.randn(2, 3)
b.a = new_value
b
[12]:
Batch(
a: tensor([[-0.3270, 0.0182, -1.7439],
[-0.0369, 0.7698, 0.8784]]),
x: Batch(
c: tensor([[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]]),
),
)
[13]:
%timeit b.a = new_value
369 ns ± 0.648 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
Initialization¶
TreeValue’s Initialization¶
[14]:
%timeit FastTreeValue(_TREE_DATA_1)
644 ns ± 0.944 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
Tianshou Batch’s Initialization¶
[15]:
%timeit Batch(**_TREE_DATA_1)
8.42 µs ± 11.1 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
Deep Copy Operation¶
[16]:
import copy
Deep Copy of TreeValue¶
[17]:
t3 = FastTreeValue(_TREE_DATA_3)
%timeit copy.deepcopy(t3)
128 µs ± 450 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Deep Copy of Tianshou Batch¶
[18]:
b3 = Batch(**_TREE_DATA_3)
%timeit copy.deepcopy(b3)
127 µs ± 590 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Stack, Concat and Split Operation¶
Performance of TreeValue¶
[19]:
trees = [FastTreeValue(_TREE_DATA_2) for _ in range(8)]
[20]:
t_stack = FastTreeValue.func(subside=True)(torch.stack)
t_stack(trees)
[20]:
[21]:
%timeit t_stack(trees)
24.4 µs ± 65 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
[22]:
t_cat = FastTreeValue.func(subside=True)(torch.cat)
t_cat(trees)
[22]:
[23]:
%timeit t_cat(trees)
22.8 µs ± 750 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
[24]:
t_split = FastTreeValue.func(rise=True)(torch.split)
tree = FastTreeValue({
'obs': torch.randn(8, 4, 84, 84),
'action': torch.randint(0, 6, size=(8, 1,)),
'reward': torch.rand(8, 1),
})
%timeit t_split(tree, 1)
51.1 µs ± 244 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Performance of Tianshou Batch¶
[25]:
batches = [Batch(**_TREE_DATA_2) for _ in range(8)]
Batch.stack(batches)
[25]:
Batch(
a: tensor([[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]],
[[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]]]),
x: Batch(
c: tensor([[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]],
[[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]]]),
),
)
[26]:
%timeit Batch.stack(batches)
63.3 µs ± 500 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
[27]:
Batch.cat(batches)
[27]:
Batch(
a: tensor([[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265],
[ 1.1200, -0.5731, 0.6099],
[-1.0565, -0.6668, 0.4265]]),
x: Batch(
c: tensor([[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425],
[-1.2412, -0.5392, -0.3254, 0.0992],
[ 1.1248, -0.0375, -0.0383, 0.1545],
[ 0.3995, -0.7661, -0.4404, -0.7425]]),
),
)
[28]:
%timeit Batch.cat(batches)
119 µs ± 995 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
[29]:
batch = Batch({
'obs': torch.randn(8, 4, 84, 84),
'action': torch.randint(0, 6, size=(8, 1,)),
'reward': torch.rand(8, 1)}
)
%timeit list(Batch.split(batch, 1, shuffle=False, merge_last=True))
276 µs ± 2.37 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
[ ]: