Skip to content

优化to_tensor函数中的bf16转换 #73050

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

Merged
merged 5 commits into from
Jun 12, 2025

Conversation

Qin-sx
Copy link
Contributor

@Qin-sx Qin-sx commented Jun 2, 2025

PR Category

User Experience

PR Types

Improvements

Description

resolve #72484

需求:

  1. 保持原numpy类型不变,直接转为一个paddle.Tensor
  2. 返回paddle.Tensor,astype为bfloat16

测试代码

import numpy as np
import paddle
import time

x = np.random.randn(100000).astype(np.float32)
tensor_bfloat16 = paddle.to_tensor(x, dtype=paddle.bfloat16)


num_runs = 1000
total_time = 0

for _ in range(num_runs):
    start_time = time.time()
    tensor_bfloat16 = paddle.to_tensor(x, dtype=paddle.bfloat16)
    paddle.device.synchronize()
    end_time = time.time()
    total_time += (end_time - start_time)

avg_time = total_time / num_runs

print(f"avg time ({num_runs} runs): {avg_time * 1000:.4f} ms")

原本方式平均耗时为 40.4780 ms, 修改后平均耗时为 0.2655 ms。

	modified:   python/paddle/tensor/creation.py
	modified:   test/dygraph_to_static/test_to_tensor.py
Copy link

paddle-bot bot commented Jun 2, 2025

你的PR提交成功,感谢你对开源项目的贡献!
请关注后续CI自动化测试结果,详情请参考Paddle-CI手册
Your PR has been submitted. Thanks for your contribution!
Please wait for the result of CI firstly. See Paddle CI Manual for details.

@paddle-bot paddle-bot bot added the contributor External developers label Jun 2, 2025
@codecov-commenter
Copy link

codecov-commenter commented Jun 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Please upload report for BASE (develop@425c14d). Learn more about missing BASE report.

Additional details and impacted files
@@             Coverage Diff             @@
##             develop    #73050   +/-   ##
===========================================
  Coverage           ?   100.00%           
===========================================
  Files              ?         1           
  Lines              ?        10           
  Branches           ?         0           
===========================================
  Hits               ?        10           
  Misses             ?         0           
  Partials           ?         0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

Choose a reason for hiding this comment

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

  1. 这段代码并没有修改静态图分支,不需要添加动转静单测,单测添加到 test/legacy_test/test_eager_tensor.py
  2. 只是加了一个普通的函数跑不到,且添加 unittest.skipIf 的方式也是错的

Copy link
Contributor Author

Choose a reason for hiding this comment

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

            tensor = core.eager.Tensor(
                value=data,
                place=place,
                persistable=False,
                zero_copy=False,
                name=None,
                stop_gradient=stop_gradient,
            )
            # tensor = tensor.astype(dtype) 
            tensor = paddle.cast(tensor, dtype)
            return tensor

您好,可否帮忙看一下,在使用转换后,x.grad会变为None

x = paddle.to_tensor( 1e6, dtype=paddle.bfloat16, stop_gradient=False)
print("x:", x)
y = x * x
y.backward()
print("x.grad:", x.grad)

修改后结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: None

原本结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -1.9988e+06)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

已修改

	modified:   python/paddle/tensor/creation.py
	modified:   test/dygraph_to_static/test_to_tensor.py
tensor.stop_gradient = stop_gradient
return tensor
else:
data = _handle_np_dtype(data, dtype)
Copy link
Contributor

Choose a reason for hiding this comment

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

可以把_handle_np_dtype逻辑挪出来,移除掉原来不正确的bf16分支代码

Copy link
Contributor Author

Choose a reason for hiding this comment

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

请问这个是指将_handle_np_dtype函数删除,然后把代码放在else:中吗?因为_handle_np_dtype函数在前面也被调用过。

Copy link
Contributor

Choose a reason for hiding this comment

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

请问这个是指将_handle_np_dtype函数删除,然后把代码放在else:中吗?因为_handle_np_dtype函数在前面也被调用过。

这个逻辑很简单,可以都挪出来,直接处理掉原来错误的bf16分支

Copy link
Contributor

Choose a reason for hiding this comment

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

这个逻辑很简单,可以都挪出来,直接处理掉原来错误的bf16分支

Copy link
Contributor Author

Choose a reason for hiding this comment

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

嗯,收到,已修改

name=None,
stop_gradient=stop_gradient,
)
tensor = tensor.detach().astype(dtype)
Copy link
Contributor

Choose a reason for hiding this comment

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

这样写呢:

tensor = core.eager.Tensor(
                value=data,
                place=place,
                persistable=False,
                zero_copy=False,
                name=None,
                stop_gradient=True,
)
tensor = tensor.astype('bfloat16')
tensor.stop_gradient = stop_gradient
return tensor

Copy link
Contributor Author

Choose a reason for hiding this comment

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

这样好像不行,上一个版本是类似的做法。我个人理解是只能数据进行转换,不能带着gradient一起转换。如果不用detach,会导致grad为None。

            tensor = core.eager.Tensor(
                value=data,
                place=place,
                persistable=False,
                zero_copy=False,
                name=None,
                stop_gradient=stop_gradient,
            )
            # tensor = tensor.astype(dtype) 
            tensor = paddle.cast(tensor, dtype)
            return tensor

您好,可否帮忙看一下,在使用转换后,x.grad会变为None

x = paddle.to_tensor( 1e6, dtype=paddle.bfloat16, stop_gradient=False)
print("x:", x)
y = x * x
y.backward()
print("x.grad:", x.grad)

修改后结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: None

原本结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -1.9988e+06)

Copy link
Contributor

Choose a reason for hiding this comment

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

这样好像不行,上一个版本是类似的做法。我个人理解是只能数据进行转换,不能带着gradient一起转换。如果不用detach,会导致grad为None。

            tensor = core.eager.Tensor(
                value=data,
                place=place,
                persistable=False,
                zero_copy=False,
                name=None,
                stop_gradient=stop_gradient,
            )
            # tensor = tensor.astype(dtype) 
            tensor = paddle.cast(tensor, dtype)
            return tensor

您好,可否帮忙看一下,在使用转换后,x.grad会变为None

x = paddle.to_tensor( 1e6, dtype=paddle.bfloat16, stop_gradient=False)
print("x:", x)
y = x * x
y.backward()
print("x.grad:", x.grad)

修改后结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: None

原本结果

x: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -9.9942e+05)
x.grad: Tensor(shape=[], dtype=bfloat16, place=Place(cpu), stop_gradient=False,
       -1.9988e+06)

这样写是可以的,这是因为之前的写法,没有设置stop_gradient=True,使得第一个tensor与cast后的tensor建立了反向关系,梯度传导到第一个tensor了,而cast后的tensor的梯度就被清理掉了。

目前把第一个tensor的stop_gradient设置为True,就避免了这个问题。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

嗯,收到,我测试了一下,确实没问题,感谢

Qin-sx added 2 commits June 7, 2025 00:02
	modified:   python/paddle/tensor/creation.py
	modified:   python/paddle/tensor/creation.py
# Windows default type is 'int32', while Linux/Mac is 'int64'. Unify they.
if data.dtype in ['int32']:
data = data.astype("int64")

if dtype:
data = _handle_np_dtype(data, dtype)
if (
Copy link
Contributor

@zhwesky2010 zhwesky2010 Jun 9, 2025

Choose a reason for hiding this comment

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

这里不用搞这么多判断吧,代码注意逻辑清晰,可读性强。

这里要么全统一用 convert_dtype(dtype) 判断,要么统一用dtype判断,不用在这里反复冗余判断。ndarray也没必要判断吧

Copy link
Contributor Author

Choose a reason for hiding this comment

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

嗯,收到,已按照下面的方式修改

tensor.stop_gradient = stop_gradient
return tensor
else:
if convert_dtype(dtype) != convert_dtype(data.dtype):
Copy link
Contributor

@zhwesky2010 zhwesky2010 Jun 9, 2025

Choose a reason for hiding this comment

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

if dtype and  convert_dtype(dtype) != convert_dtype(data.dtype):
        if convert_dtype(dtype) == 'uint16':
             ...
        else:
             data = data.astype(convert_dtype(dtype))

这样可以吗,这里的分支显得又多又乱

Copy link
Contributor Author

Choose a reason for hiding this comment

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

嗯,收到,已修改,感谢

@@ -757,13 +742,35 @@ def _handle_np_dtype(
if default_type in ['float16', 'float32']
else 'complex128'
)
data = _handle_np_dtype(data, default_type)
if convert_dtype(default_type) != convert_dtype(data.dtype):
Copy link
Contributor

@zhwesky2010 zhwesky2010 Jun 9, 2025

Choose a reason for hiding this comment

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

这里统一写成:

if convert_dtype(default_type) != convert_dtype(data.dtype):
    dtype = default_type

然后交到下面的逻辑里去处理,代码更简洁

Copy link
Contributor Author

Choose a reason for hiding this comment

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

嗯,收到,已修改,感谢

Copy link
Contributor

@zhwesky2010 zhwesky2010 left a comment

Choose a reason for hiding this comment

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

代码注意下可读性方面

	modified:   python/paddle/tensor/creation.py
Copy link
Contributor

@zhwesky2010 zhwesky2010 left a comment

Choose a reason for hiding this comment

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

LGTM

@zhwesky2010 zhwesky2010 merged commit d2d3b1b into PaddlePaddle:develop Jun 12, 2025
50 checks passed
shanjiang7 pushed a commit to shanjiang7/Paddle that referenced this pull request Jun 12, 2025
* optimized bf16 convert in to_tensor

	modified:   python/paddle/tensor/creation.py
	modified:   test/dygraph_to_static/test_to_tensor.py

* modified for grad

	modified:   python/paddle/tensor/creation.py
	modified:   test/dygraph_to_static/test_to_tensor.py

* changed core.eager.Tensor para

	modified:   python/paddle/tensor/creation.py

* deleted _handle_np_dtype

	modified:   python/paddle/tensor/creation.py

* updated conditions

	modified:   python/paddle/tensor/creation.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributor External developers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Paddle 的 to_tensor()方法和 torch 的 tensor()方法的行为不一致
4 participants