mirror of
https://github.com/tile-ai/tilelang.git
synced 2026-10-22 06:50:25 +08:00
* Enhance Cast vectorized * Add Parallel vectorized cast test * code lint * merge newest commit
108 lines
3.4 KiB
Python
108 lines
3.4 KiB
Python
import torch
|
|
import tilelang.testing
|
|
import tilelang.language as T
|
|
|
|
str2dtype = {
|
|
"float32": torch.float32,
|
|
"float16": torch.float16,
|
|
"bfloat16": torch.bfloat16,
|
|
"float8_e4m3": torch.float8_e4m3fn,
|
|
"float8_e5m2": torch.float8_e5m2,
|
|
}
|
|
|
|
|
|
@tilelang.jit
|
|
def vectorized_cast_kernel(M: int, dtype_A: str, dtype_B: str):
|
|
assert M % 256 == 0
|
|
|
|
@T.prim_func
|
|
def main(
|
|
A: T.Tensor[(M,), dtype_A], # noqa: F821
|
|
B: T.Tensor[(M,), dtype_B], # noqa: F821
|
|
):
|
|
with T.Kernel(1, threads=128):
|
|
T.copy(A, B)
|
|
|
|
return main
|
|
|
|
|
|
@tilelang.jit
|
|
def parallel_vectorized_cast_kernel(M: int, dtype_A: str, dtype_B: str):
|
|
assert M % 256 == 0
|
|
|
|
@T.prim_func
|
|
def main(
|
|
A: T.Tensor[(M,), dtype_A], # noqa: F821
|
|
B: T.Tensor[(M,), dtype_B], # noqa: F821
|
|
):
|
|
with T.Kernel(1, threads=128):
|
|
A_local = T.alloc_fragment((M,), dtype_A)
|
|
B_local = T.alloc_fragment((M,), dtype_B)
|
|
|
|
T.copy(A, A_local)
|
|
for i in T.Parallel(M):
|
|
B_local[i] = A_local[i]
|
|
T.copy(B_local, B)
|
|
|
|
return main
|
|
|
|
|
|
def run_vectorized_cast(src_dtype_str: str, dst_dtype_str: str, check_str: str, lanes: int = 2):
|
|
"""Run the vectorized cast kernel and check the correctness.
|
|
Args:
|
|
src_dtype_str: The source data type string.
|
|
dst_dtype_str: The destination data type string.
|
|
check_str: Used to ensure vectorized cast is used.
|
|
lanes: The number of lanes of the source and destination data types.
|
|
"""
|
|
|
|
M = 128 * lanes
|
|
kernel = vectorized_cast_kernel(M, src_dtype_str, dst_dtype_str)
|
|
kernel_parallel = parallel_vectorized_cast_kernel(M, src_dtype_str, dst_dtype_str)
|
|
|
|
A = torch.randn(M, dtype=str2dtype[src_dtype_str]).cuda()
|
|
B = torch.zeros(M, dtype=str2dtype[dst_dtype_str]).cuda()
|
|
C = torch.zeros(M, dtype=str2dtype[dst_dtype_str]).cuda()
|
|
|
|
kernel(A, B)
|
|
kernel_parallel(A, C)
|
|
|
|
torch.testing.assert_close(A.to(str2dtype[dst_dtype_str]), B)
|
|
torch.testing.assert_close(A.to(str2dtype[dst_dtype_str]), C)
|
|
|
|
code = kernel.get_kernel_source()
|
|
code_parallel = kernel_parallel.get_kernel_source()
|
|
|
|
assert check_str in code and check_str in code_parallel, \
|
|
f"Cast {src_dtype_str} to {dst_dtype_str} with {lanes=} is not vectorized!"
|
|
|
|
|
|
def test_vectorized_cast():
|
|
# fp32 -> fp16
|
|
run_vectorized_cast("float32", "float16", "__float22half2_rn", 2)
|
|
run_vectorized_cast("float32", "float16", "__float22half2_rn", 4)
|
|
|
|
# fp16 -> fp32
|
|
run_vectorized_cast("float16", "float32", "__half22float2", 2)
|
|
run_vectorized_cast("float16", "float32", "__half22float2", 4)
|
|
|
|
# fp32 -> fp8_e4m3
|
|
run_vectorized_cast("float32", "float8_e4m3", "__nv_cvt_float2_to_fp8x2", 2)
|
|
run_vectorized_cast("float32", "float8_e4m3", "__nv_cvt_float2_to_fp8x2", 4)
|
|
|
|
# fp32 -> fp8_e5m2
|
|
run_vectorized_cast("float32", "float8_e5m2", "__nv_cvt_float2_to_fp8x2", 2)
|
|
run_vectorized_cast("float32", "float8_e5m2", "__nv_cvt_float2_to_fp8x2", 4)
|
|
|
|
# fp32 -> bf16
|
|
run_vectorized_cast("float32", "bfloat16", "__float22bfloat162_rn", 2)
|
|
run_vectorized_cast("float32", "bfloat16", "__float22bfloat162_rn", 4)
|
|
|
|
# bf16 -> fp32
|
|
run_vectorized_cast("bfloat16", "float32", "__bfloat1622float2", 2)
|
|
run_vectorized_cast("bfloat16", "float32", "__bfloat1622float2", 4)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
tilelang.testing.main()
|