Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Hackathon 5th No.36】 为 Paddle 新增 matrix_exp API #775

Merged
merged 4 commits into from
Dec 18, 2023

Conversation

megemini
Copy link
Contributor

@megemini megemini commented Dec 6, 2023

PR types

New features

PR changes

Docs

Description

【Hackathon 5th No.36】 为 Paddle 新增 matrix_exp API

参考 RFC: #674

做如下修改:

  • 增加 Eigen 的实现
  • 实现方式为 python,列举涉及到的 paddle api
  • 不涉及底层 op
    主要是因为这样相对简单稳妥 ~ 🤣🤣🤣
    tensorflow、eigen、scipy 都是使用的 pade 近似,可以作为参考 ~
    pytorch 是用的 2019 年较新发表论文的泰勒多项式算法,参考资料较少,底层算子也可能存在不兼容情况 ~

参考实现方式:PaddlePaddle/Paddle#59715

@luotao1 @cxxly @zade23

请评审 ~ 谢谢!

Copy link

paddle-bot bot commented Dec 6, 2023

你的PR提交成功,感谢你对开源项目的贡献!
请检查PR提交格式和内容是否完备,具体请参考示例模版
Your PR has been submitted. Thanks for your contribution!
Please check its format and content. For this, you can refer to Template and Demo.

- paddle.isfinite
- paddle.linalg.solve
- paddle.static.nn.cond
- paddle.static.nn.while_loop
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要控制流的原因是?这两个API支持静态图,并且有些bug,能否使用其它API代替

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个算法是个近似算法,计算的时候会有逻辑判断,参考一下 eigen 的实现:
https://eigen.tuxfamily.org/dox/unsupported/MatrixExponential_8h_source.html

 template <typename MatrixType>
 struct matrix_exp_computeUV<MatrixType, double>
 {
   typedef typename NumTraits<typename traits<MatrixType>::Scalar>::Real RealScalar;
   template <typename ArgType>
   static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
   {
     using std::frexp;
     using std::pow;
     const RealScalar l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
     squarings = 0;
     if (l1norm < 1.495585217958292e-002) {
       matrix_exp_pade3(arg, U, V);
     } else if (l1norm < 2.539398330063230e-001) {
       matrix_exp_pade5(arg, U, V);
     } else if (l1norm < 9.504178996162932e-001) {
       matrix_exp_pade7(arg, U, V);
     } else if (l1norm < 2.097847961257068e+000) {
       matrix_exp_pade9(arg, U, V);
     } else {
       const RealScalar maxnorm = 5.371920351148152;
       frexp(l1norm / maxnorm, &squarings);
       if (squarings < 0) squarings = 0;
       MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<RealScalar>(squarings));
       matrix_exp_pade13(A, U, V);
     }
   }
 };

这是其中一段 uv 的计算,会不断的比对 l1norm 和一些常数 ~

paddle 实现的话如果涉及到比对 tensor 和 数值,之前尝试过用 if 来实现,不过静态图好像会有问题?所以只能用 paddle.static.nn.cond paddle.static.nn.while_loop?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个逻辑用python去组,确实会有问题,除非写到kernel中可以避免控制流。这个待定吧,先把前面两种算法性能测试验证完,如果选型是torch算法,可能实现为一个kernel更合适;如果选型是近似算法,可以按照这个思路实现一半,验证一下,如果静态图有问题,可以做下降级,先支持动态图版本(这个我去确认下)


使用 python 实现,不涉及底层 op。

## API实现方案
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

竞品调研中提到了pade近似及泰勒级数两种算法,这两种算法优劣需要对比,并且需要说明下Paddle实现基哪种方案


该 API 实现于 `python/paddle/tensor/linalg.py`.

涉及到的 paddle api 主要有:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以再补充下基于这些实现该API伪代码,进一步降低实现上的风险

* 对于参数异常值输入,例如x的不合法值等,应该有友好的报错信息及异常反馈,需要有相关测试Case验证。

# 七、可行性分析和排期规划
技术可行性:参考同类项目和相似的 API,相关内容参考丰富,无重大难点;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果需要用到控制流,是一个比较大的风险点,目前飞桨控制流支持尚不完善,在快速迭代中

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个算法好像不用控制流没法做,tensorflow, eigen, scipy 里面的 pade 近似都是比对 l1norm 实现的 ~ 😂

@megemini
Copy link
Contributor Author

megemini commented Dec 8, 2023

Update 20231208

  • 增加泰勒多项式与帕德近似的对比
  • 增加实现方案的伪代码
  • 增加风险提示

这个实现方案用的帕德近似,里面涉及到很多的数值对比,因此需要用到控制流 (if/while 静态图好像不能用?)~

实际上,pytorch 的泰勒多项式算法,也会涉及到数值对比 ~

matrix exp 算法涉及到的数学内容较多,本人能力有限,也只能参考各个实现方法,然后转换为 paddle 能够实现的方式 ~ 🤣🤣🤣

@cxxly 请评审 ~ 谢谢!

@megemini megemini requested a review from cxxly December 8, 2023 11:29

PyTorch 的实现基于上述论文,发表于 2019 年,参考资料较少。

基于此,本次实现基于 Pade 近似的方式,并且考虑到算子兼容情况,使用 python 的实现方式。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pytorch目前是使用最为广泛的框架,并且也是飞桨主要竞品;需要进一步测试,验证下性能及精度差距。比如,可以用tf和torch对比下性能和精度。如果性能/精度差距较大,还是选择更好的算法。先不用担心实现的问题,如果实现难度较大,我们可以提升题目难度。

@megemini
Copy link
Contributor Author

megemini commented Dec 13, 2023

pytorch目前是使用最为广泛的框架,并且也是飞桨主要竞品;需要进一步测试,验证下性能及精度差距。比如,可以用tf和torch对比下性能和精度。如果性能/精度差距较大,还是选择更好的算法。

嗯,其实我自己也比较好奇,这几天就想测试一下的 ~ 刚抽出时间来测了一下:

我在本地测试的,cpu 是 i5-12400,ubutnu 22.04 ~

In [1]: import paddle

In [3]: import torch

In [4]: import tensorflow as tf

In [6]: import numpy as np

In [8]: import math

In [9]: m = np.array([[0, math.pi/3], [-math.pi/3, 0]])

In [10]: m_torch = torch.tensor(m)

In [11]: me_torch = torch.linalg.matrix_exp(m_torch)

In [12]: m_tf = tf.convert_to_tensor(m)

In [13]: me_tf = tf.linalg.expm(m_tf)

In [14]: import scipy

In [15]: me_scipy = scipy.linalg.expm(m)

In [18]: m_paddle = paddle.to_tensor(m)

In [23]: me_paddle = matrix_exp(m_paddle)

In [25]: 

In [25]: %timeit me_torch = torch.linalg.matrix_exp(m_torch)
45 µs ± 695 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [26]: %timeit me_torch = torch.linalg.matrix_exp(m_torch)
45.6 µs ± 865 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [27]: %timeit me_tf = tf.linalg.expm(m_tf)
4.73 ms ± 45.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [28]: %timeit me_tf = tf.linalg.expm(m_tf)
4.7 ms ± 34.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [29]: %timeit me_scipy = scipy.linalg.expm(m)
30.1 µs ± 486 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [30]: %timeit me_scipy = scipy.linalg.expm(m)
30 µs ± 544 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [31]: %timeit me_paddle = matrix_exp(m_paddle)
1.15 ms ± 7.34 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [32]: %timeit me_paddle = matrix_exp(m_paddle)
1.14 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [33]: 

In [33]: 

In [36]: s_a = np.random.rand(2, 3, 3)

In [37]: s_b = np.random.rand(2, 3, 4)

In [38]: s_a_torch = torch.tensor(s_a)

In [39]: s_b_torch = torch.tensor(s_b)

In [41]: %timeit torch.linalg.solve(s_a_torch, s_b_torch)
9.2 µs ± 65.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [42]: s_a_paddle = paddle.to_tensor(s_a)

In [43]: s_b_paddle = paddle.to_tensor(s_b)

In [45]: %timeit paddle.linalg.solve(s_a_paddle, s_b_paddle)
43 µs ± 1.55 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [46]: 

In [46]: def max_diff(a, b):
    ...:     return np.max(np.abs(a-b))
    ...: 

In [47]: def max_rela(a, b):
    ...:     diff = np.abs(a-b)
    ...:     return np.max(diff/np.abs(a))
    ...: 

In [48]: max_diff(me_scipy, me_paddle.numpy())
Out[48]: 1.1102230246251565e-16

In [50]: max_diff(me_scipy, me_torch.numpy())
Out[50]: 3.3306690738754696e-16

In [51]: max_diff(me_scipy, me_tf.numpy())
Out[51]: 1.1102230246251565e-16

In [52]: max_rela(me_scipy, me_paddle.numpy())
Out[52]: 1.2819751242557095e-16

In [53]: max_rela(me_scipy, me_torch.numpy())
Out[53]: 3.845925372767128e-16

In [54]: max_rela(me_scipy, me_tf.numpy())
Out[54]: 1.2819751242557095e-16

In [55]: max_diff(me_torch.numpy(), me_paddle.numpy())
Out[55]: 4.440892098500626e-16

In [56]: max_diff(me_torch.numpy(), me_scipy)
Out[56]: 3.3306690738754696e-16

In [57]: max_diff(me_torch.numpy(), me_tf.numpy())
Out[57]: 4.440892098500626e-16

In [58]: max_rela(me_torch.numpy(), me_paddle.numpy())
Out[58]: 5.12790049702284e-16

In [59]: max_rela(me_torch.numpy(), me_scipy)
Out[59]: 3.8459253727671296e-16

In [60]: max_rela(me_torch.numpy(), me_tf.numpy())
Out[60]: 5.12790049702284e-16

In [62]: tf.__version__
Out[62]: '2.13.1'

In [63]: torch.__version__
Out[63]: '2.1.1+cpu'

上面代码是直接从 ipython 中拷贝出来的,只把中间一些输入错误给删掉了,如有疑问可以在其他地方复现 ~

测试分三部分:

  • 测试 scipy/tensorflow/torch/paddle 的性能,使用 timeit ~
    结论:

    • torch 与 scipy 速度最快,在一个量级 ~
    • tensorflow 与 paddle 速度在一个量级,慢于 torch 和 scipy ~
    • torch (45 µs ± 695 ns) 比 scipy (30.1 µs ± 486 ns) 慢 ~
    • paddle (1.14 ms ± 14.7 µs) 比 torch (45 µs ± 695 ns) 慢较多 ~
    • paddle (1.14 ms ± 14.7 µs) 比 tensorflow (4.7 ms ± 34.2 µs) 快一些 ~

    分析主要原因:

    • paddle 用 python 实现的,torch 用 c++ 实现,因此 torch 快于 paddle ~
    • 至于 torch 算法导致的性能提升,可能不大 ~ 因为 scipy 也是用的 pade 近似,与 paddle 一样,scipy 快的主要原因应该是用 Cython 实现了较耗时的操作 ~ 另外,torch 本身框架也会消耗一部分时间 ~
  • 测试 torch 与 paddle 的 solve 性能,使用 timeit ~
    结论:

    • torch (9.2 µs ± 65.7 ns ) 快于 paddle (43 µs ± 1.55 µs) ~

    之所以要测这个是因为,两者都是 c++ 算子,而 paddle 也慢于 torch,因此,即使 matrix_exp 用 c++ 实现,也未必会比 torch 快 ... ... 不过,当然,用 c++ 实现一定会快于 python的 ~

  • 测试 scipy/tensorflow/torch/paddle 的精度,使用绝对误差 (max_diff) 与相对误差 (max_rela) ~
    由于 matrix_exp 本身就是个近似算法,不管使用 pade 近似还是泰勒多项式,所以,直接说结论:

    • 几乎都差不多 (1e-16) ,应该可以忽略不计吧 ~

先不用担心实现的问题,如果实现难度较大,我们可以提升题目难度。

这里可能误解我的意思了,我是想说,目前只有 pade 近似与泰勒多项式可以参考,我也想不出第三种算法,或者更快的算法,这是个数学问题,提升多少难度也做不到啊 ~~~ 🫣🫣🫣

所以,如果用 python 实现,可以参考 tensoflow/scipy,如果用 c++ 实现,可以参考 eigen,如果用 c++ 的泰勒多项式实现,可以参考 torch ~ 这里选择了 python 实现,因为 c++ 写起来太麻烦了 ~~~ 😂😂😂

另外,关于控制流目前不稳定的问题,我觉得还好,毕竟最后发布版本的时候总不能跟用户说这个控制流不能用吧 ~~~ 😂😂😂

@cxxly 请阅 ~

@megemini
Copy link
Contributor Author

Update 20231214

现在程序里面很多是兼顾静态图的地方,如 paddle.full ~ 如果单独调试动态图性能的话,刚才试了一下,能提升一倍吧:

In [12]: %timeit me_paddle = matrix_exp(m_paddle)
533 µs ± 3.29 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

@cxxly
Copy link

cxxly commented Dec 14, 2023

pytorch目前是使用最为广泛的框架,并且也是飞桨主要竞品;需要进一步测试,验证下性能及精度差距。比如,可以用tf和torch对比下性能和精度。如果性能/精度差距较大,还是选择更好的算法。

嗯,其实我自己也比较好奇,这几天就想测试一下的 ~ 刚抽出时间来测了一下:

我在本地测试的,cpu 是 i5-12400,ubutnu 22.04 ~

In [1]: import paddle

In [3]: import torch

In [4]: import tensorflow as tf

In [6]: import numpy as np

In [8]: import math

In [9]: m = np.array([[0, math.pi/3], [-math.pi/3, 0]])

In [10]: m_torch = torch.tensor(m)

In [11]: me_torch = torch.linalg.matrix_exp(m_torch)

In [12]: m_tf = tf.convert_to_tensor(m)

In [13]: me_tf = tf.linalg.expm(m_tf)

In [14]: import scipy

In [15]: me_scipy = scipy.linalg.expm(m)

In [18]: m_paddle = paddle.to_tensor(m)

In [23]: me_paddle = matrix_exp(m_paddle)

In [25]: 

In [25]: %timeit me_torch = torch.linalg.matrix_exp(m_torch)
45 µs ± 695 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [26]: %timeit me_torch = torch.linalg.matrix_exp(m_torch)
45.6 µs ± 865 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [27]: %timeit me_tf = tf.linalg.expm(m_tf)
4.73 ms ± 45.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [28]: %timeit me_tf = tf.linalg.expm(m_tf)
4.7 ms ± 34.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [29]: %timeit me_scipy = scipy.linalg.expm(m)
30.1 µs ± 486 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [30]: %timeit me_scipy = scipy.linalg.expm(m)
30 µs ± 544 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [31]: %timeit me_paddle = matrix_exp(m_paddle)
1.15 ms ± 7.34 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [32]: %timeit me_paddle = matrix_exp(m_paddle)
1.14 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [33]: 

In [33]: 

In [36]: s_a = np.random.rand(2, 3, 3)

In [37]: s_b = np.random.rand(2, 3, 4)

In [38]: s_a_torch = torch.tensor(s_a)

In [39]: s_b_torch = torch.tensor(s_b)

In [41]: %timeit torch.linalg.solve(s_a_torch, s_b_torch)
9.2 µs ± 65.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [42]: s_a_paddle = paddle.to_tensor(s_a)

In [43]: s_b_paddle = paddle.to_tensor(s_b)

In [45]: %timeit paddle.linalg.solve(s_a_paddle, s_b_paddle)
43 µs ± 1.55 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [46]: 

In [46]: def max_diff(a, b):
    ...:     return np.max(np.abs(a-b))
    ...: 

In [47]: def max_rela(a, b):
    ...:     diff = np.abs(a-b)
    ...:     return np.max(diff/np.abs(a))
    ...: 

In [48]: max_diff(me_scipy, me_paddle.numpy())
Out[48]: 1.1102230246251565e-16

In [50]: max_diff(me_scipy, me_torch.numpy())
Out[50]: 3.3306690738754696e-16

In [51]: max_diff(me_scipy, me_tf.numpy())
Out[51]: 1.1102230246251565e-16

In [52]: max_rela(me_scipy, me_paddle.numpy())
Out[52]: 1.2819751242557095e-16

In [53]: max_rela(me_scipy, me_torch.numpy())
Out[53]: 3.845925372767128e-16

In [54]: max_rela(me_scipy, me_tf.numpy())
Out[54]: 1.2819751242557095e-16

In [55]: max_diff(me_torch.numpy(), me_paddle.numpy())
Out[55]: 4.440892098500626e-16

In [56]: max_diff(me_torch.numpy(), me_scipy)
Out[56]: 3.3306690738754696e-16

In [57]: max_diff(me_torch.numpy(), me_tf.numpy())
Out[57]: 4.440892098500626e-16

In [58]: max_rela(me_torch.numpy(), me_paddle.numpy())
Out[58]: 5.12790049702284e-16

In [59]: max_rela(me_torch.numpy(), me_scipy)
Out[59]: 3.8459253727671296e-16

In [60]: max_rela(me_torch.numpy(), me_tf.numpy())
Out[60]: 5.12790049702284e-16

In [62]: tf.__version__
Out[62]: '2.13.1'

In [63]: torch.__version__
Out[63]: '2.1.1+cpu'

上面代码是直接从 ipython 中拷贝出来的,只把中间一些输入错误给删掉了,如有疑问可以在其他地方复现 ~

测试分三部分:

  • 测试 scipy/tensorflow/torch/paddle 的性能,使用 timeit ~
    结论:

    • torch 与 scipy 速度最快,在一个量级 ~
    • tensorflow 与 paddle 速度在一个量级,慢于 torch 和 scipy ~
    • torch (45 µs ± 695 ns) 比 scipy (30.1 µs ± 486 ns) 慢 ~
    • paddle (1.14 ms ± 14.7 µs) 比 torch (45 µs ± 695 ns) 慢较多 ~
    • paddle (1.14 ms ± 14.7 µs) 比 tensorflow (4.7 ms ± 34.2 µs) 快一些 ~

    分析主要原因:

    • paddle 用 python 实现的,torch 用 c++ 实现,因此 torch 快于 paddle ~
    • 至于 torch 算法导致的性能提升,可能不大 ~ 因为 scipy 也是用的 pade 近似,与 paddle 一样,scipy 快的主要原因应该是用 Cython 实现了较耗时的操作 ~ 另外,torch 本身框架也会消耗一部分时间 ~
  • 测试 torch 与 paddle 的 solve 性能,使用 timeit ~
    结论:

    • torch (9.2 µs ± 65.7 ns ) 快于 paddle (43 µs ± 1.55 µs) ~

    之所以要测这个是因为,两者都是 c++ 算子,而 paddle 也慢于 torch,因此,即使 matrix_exp 用 c++ 实现,也未必会比 torch 快 ... ... 不过,当然,用 c++ 实现一定会快于 python的 ~

  • 测试 scipy/tensorflow/torch/paddle 的精度,使用绝对误差 (max_diff) 与相对误差 (max_rela) ~
    由于 matrix_exp 本身就是个近似算法,不管使用 pade 近似还是泰勒多项式,所以,直接说结论:

    • 几乎都差不多 (1e-16) ,应该可以忽略不计吧 ~

先不用担心实现的问题,如果实现难度较大,我们可以提升题目难度。

这里可能误解我的意思了,我是想说,目前只有 pade 近似与泰勒多项式可以参考,我也想不出第三种算法,或者更快的算法,这是个数学问题,提升多少难度也做不到啊 ~~~ 🫣🫣🫣

所以,如果用 python 实现,可以参考 tensoflow/scipy,如果用 c++ 实现,可以参考 eigen,如果用 c++ 的泰勒多项式实现,可以参考 torch ~ 这里选择了 python 实现,因为 c++ 写起来太麻烦了 ~~~ 😂😂😂

另外,关于控制流目前不稳定的问题,我觉得还好,毕竟最后发布版本的时候总不能跟用户说这个控制流不能用吧 ~~~ 😂😂😂

@cxxly 请阅 ~

好的,感谢补充测试数据。从当前结论上来看,pade近似和泰勒多项式算法自身性能和精度近似,主要性能diff在python与c++ bind overhead,这个个人认为可以接受,后续模型实际应用如果有较大差距,可以再下沉优化,成本也不高。

另外这个测试数据形状比较小,缺少GPU测试,需要再进一步验证以验证上述结论solid。 1)数据量较大情况(超过2000个元素) 2) GPU测试,可以用AI Studio环境,仅对比 tf与torch就行 。测试结论补充到设计文档。

至于控制流问题,只有部分场景(跨block微分)有些问题,可以实现一版,测试下静态图能否跑通。

我们还是首要追求工程质量,不放过每一个细节。如果可能延期,可以随时提出,会协助帮忙向活动产品运营同学申请。同时也会同步Review PR,如果上述结论没问题,会协助尽快合入,再次感谢。

@megemini
Copy link
Contributor Author

另外这个测试数据形状比较小,缺少GPU测试,需要再进一步验证以验证上述结论solid。 1)数据量较大情况(超过2000个元素) 2) GPU测试,可以用AI Studio环境,仅对比 tf与torch就行 。测试结论补充到设计文档。

aistudio 不能用 tf 和 torch ~~~ 🤣🤣🤣

稍后我在本地再测一下大数据量的情况,然后更新 rfc ~

至于控制流问题,只有部分场景(跨block微分)有些问题,可以实现一版,测试下静态图能否跑通。

我们还是首要追求工程质量,不放过每一个细节。如果可能延期,可以随时提出,会协助帮忙向活动产品运营同学申请。同时也会同步Review PR,如果上述结论没问题,会协助尽快合入,再次感谢。

赞!!!

@cxxly PaddlePaddle/Paddle#59715 这个 pr 已经验证了,旧 ir 是可以跑通的,pir 研发那边说还没做,后面可以验证 ~~~

@megemini
Copy link
Contributor Author

megemini commented Dec 15, 2023

Update 20231215

  • 增加性能对比
  • 增加精度对比

这里简单摘抄:


性能:

框架 2*2 48*48 8*32*32*32
Scipy 33.3 µs ± 424 ns 109 µs ± 1.4 µs 12.5 ms ± 158
PyTorch(cpu) 48.6 µs ± 543 ns 129 µs ± 1.7 µs 11.8 ms ± 117 µs
Tensorflow(cpu) 3.17 ms ± 69.9 µs 3.74 ms ± 33.8 µs 38.8 ms ± 1.99 ms
Tensorflow(gpu) 4.8 ms ± 69 µs 5.39 ms ± 44.9 µs 20.4 ms ± 898 µs
Paddle(cpu) 598 µs ± 9.21 µs 1.1 ms ± 15.6 µs 49.6 ms ± 809 µs
Paddle(gpu) 1.01 ms ± 7.66 µs 1.57 ms ± 6.62 µs 14.8 ms ± 9.86 µs

结论:

  • torch 与 scipy 速度最快,在一个量级
  • tensorflow 与 paddle 速度在一个量级,慢于 torch 和 scipy
  • 2000 元素量级以内, torch 比 scipy 慢
  • 200000 元素量级, torch 比 scipy 快
  • paddle 比 torch 慢较多
  • paddle 比 tensorflow 快
  • 当元素量级增大之后,这几者之间的差距在缩小
  • 2000 元素量级以内,使用 cpu 要快于 gpu
  • 200000 元素量级,gpu 要快于 cpu

分析主要原因:

  • paddle 用 python 实现的,torch 用 c++ 实现,因此 torch 快于 paddle
  • 至于 torch 算法导致的性能提升,可能不大。因为 scipy 也是用的 pade 近似,与 paddle 一样,scipy 快的主要原因应该是用 Cython 实现了较耗时的操作。另外,torch 本身框架也会消耗一部分时间。
  • 当元素量级增大之后,各框架底层算子的性能,如 solve,起主导作用,几者像差不大。
  • 当元素量级增大之后,gpu 性能得到体现,要快于 cpu 。

精度:

框架 max_rela max_diff
PyTorch 3.4541124397028097e-15 1.7285346984863281e-06
Tensorflow 3.995791166252789e-14 2.3484230041503906e-05
Paddle 4.0382001292068676e-14 2.384185791015625e-05

结论:

  • 三者相对 Scipy 精度相差不大

另外,当输入增大时,精度误差同步增大。


这里与之前的测试主要区别:

  • 增加了 paddle 与 tensorflow 在 cpu 上的性能测试
    在 48*48 及以下看到,cpu 比 gpu 性能好,而在 8*32*32*32 的大规模上 gpu 好于 cpu
  • 误差精度测试由之前的 2*2 增加到 48*48
    这样可以增大误差,更有说服力吧

另外,pytorch 的 gpu 版本不知道为啥装不上,也就没测试 ~~~

p.s. 从 48*48 增加到 8*32*32*32 测试的性能数据挺有意思的,tf 的 gpu 慢了 4 倍,paddle 的 gpu 慢了 10 倍 ~ torch 的 cpu 慢了 100 倍, paddle 的 cpu 慢了 50 倍,tf 的 cpu 慢了 10 倍 ~~~

@cxxly 请阅 ~

Copy link

@cxxly cxxly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@luotao1 luotao1 merged commit bd4afc3 into PaddlePaddle:master Dec 18, 2023
1 check passed
@megemini
Copy link
Contributor Author

Update 20231218

重新装了 torch 的 nightly version,补充测试数据:

In [30]: torch.__version__
Out[30]: '2.3.0.dev20231217+cu121'
框架 2*2 48*48 8*32*32*32
Scipy 33.3 µs ± 424 ns 109 µs ± 1.4 µs 12.5 ms ± 158 µs
PyTorch(cpu) 48.6 µs ± 543 ns 129 µs ± 1.7 µs 11.8 ms ± 117 µs
PyTorch(gpu) 106 µs ± 25.6 µs 145 µs ± 146 ns 9.89 ms ± 21.3 µs
Tensorflow(cpu) 3.17 ms ± 69.9 µs 3.74 ms ± 33.8 µs 38.8 ms ± 1.99 ms
Tensorflow(gpu) 4.8 ms ± 69 µs 5.39 ms ± 44.9 µs 20.4 ms ± 898 µs
Paddle(cpu) 598 µs ± 9.21 µs 1.1 ms ± 15.6 µs 49.6 ms ± 809 µs
Paddle(gpu) 1.01 ms ± 7.66 µs 1.57 ms ± 6.62 µs 14.8 ms ± 9.86 µs

结论跟之前的一样:中小数据量,cpu 好于 gpu,大数据量 gpu 好于 cpu ~ 但是 torch 的 gpu 性能提升很小 ~

@cxxly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants