十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Taichi 内核循环累加结果变成 0:静态类型精度丢失问题怎么排查?

Taichi 内核循环累加结果变成 0:静态类型精度丢失问题怎么排查? Taichi 内核循环累加结果变成 0静态类型精度丢失问题怎么排查【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi如果你在 Taichi 内核ti.kernel里用 for 循环累加一个小数值循环结束后print出来的结果却是0而这段代码换成原生 Python 完全正常那么先检查一个文档明确列出的常见原因累加变量用整数字面量初始化被静态推断为int32随后每次把float32的累加结果截断存回int32。Taichi 的调试文档在 Debugging tips 中给出了可复现的最小用例、编译器警告和对应修复方式Debugging类型推断的完整规则见 Type System。现象复现文档给出的最小用例以下是调试文档中原始的用例可直接用于对照你遇到的现象ti.kernel def buggy(): ret 0 # 0 is an integer, so ret is typed as int32 for i in range(3): ret 0.1 * i # i32 f32, the result is still stored in int32! print(ret) # will show 0 buggy()文档示例的运行输出[W 06/27/20 21:43:51.853] [type_check.cpp:visit66] [$19] Atomic add (float32 to int32) may lose precision.排查的第一步就是看这行编译器警告。文档对它的解释是当 Taichi 把float32结果转换为int32时会发生精度丢失。你不需要等到看到0这个结果才怀疑——只要编译期出现may lose precision这类警告就按静态类型丢失精度的方向排查。先确认累加变量的静态类型Taichi 把 Python 代码翻译为静态类型语言这与原生 Python 的行为差异是根因所在。调试文档给出的规则是在 Taichi scope 中变量的类型在初始化时确定此后不再改变。Type System 文档进一步说明变量一旦声明就不能被赋予不同类型赋值不同精度的值时会发生隐式转换。可以用文档中ti.static_print的既有用法来打印编译期类型它是编译期一次性输出不产生运行时开销import taichi as ti x ti.field(ti.f32, (2, 3)) ti.kernel def inside_taichi_scope(): ti.static_print(x.dtype) # DataType.float32 for i in range(4): ti.static_print(i.dtype) # DataType.int32 # Only print once上面的x.dtype/i.dtype打印调用是文档中的原例对可疑的累加变量套用同样的ti.static_print(变量.dtype)写法即可确认它实际是DataType.int32还是DataType.float32。如果确认是整型问题就落在这个变量的初始化值上。另外注意 Type System 文档指出的一个伴生现象当高精度的值被赋给低精度的变量时会给出精度丢失警告。例如ti.kernel def foo(): a 1 a 3.14 print(a) # 3a因初始化值为1而被定为整型随后3.14被隐式转换为3并产生警告。这和循环累加成0是同一类问题变量类型只由第一次初始化决定。文档明确提示隐式类型转换是一个重要的错误来源建议显式指定所有变量和运算的数据类型。修复把初始化值改成浮点字面量文档给出的修复方式是让初始化值本身是浮点数使变量从第一次初始化起就被定为float32ti.kernel def not_buggy(): ret 0.0 # 0 is a floating point number, so ret is typed as float32 for i in range(3): ret 0.1 * i # f32 f32. OK! print(ret) # will show 0.6 not_buggy()注意不能指望先声明为整型、后面再重新赋值浮点数来改类型——静态类型在初始化后不再改变重新赋值只会触发截断。验证修复结果编译期不再出现may lose precision警告用ti.static_print打印该变量类型应为DataType.float32。运行期文档注释给出该用例的预期输出为0.60.1 * (0 1 2) 0.6文档原例注释即# will show 0.6。如果修复后ti.static_print显示类型已变为浮点、但数值仍不符合预期再回到 Type System 文档核对每一步二元运算的隐式转换规则整型 浮点 - 浮点低精度 高精度 - 高精度冲突时按规则优先级取最高优先级规则确认是否在其他运算处仍发生了向低精度变量的赋值。相关边界默认类型与显式转换以下事实来自 Type System 文档影响你对变量为什么是这个类型的判断Taichi 初始化时默认ti.i32是默认整型、ti.f32是默认浮点型在 Taichi scope 中int与float只是这两个默认类型的别名。默认浮点型为ti.f32时字面量会被截断到约 7 位有效数字文档建议对工程仿真等需要高精度的场景使用ti.init(default_fpti.f64)把默认浮点型改为ti.f64。这是一个可选配置只在精度需求超出f32时才需要。如果确实需要切换类型文档推荐显式转换而非依赖隐式转换ti.kernel def foo(): a 3.14 b ti.cast(a, ti.i32) # 3 c ti.cast(b, ti.f32) # 3.0一句话收束这个排查路径循环累加出0时先看编译期是否出现may lose precision警告再用ti.static_print确认累加变量是DataType.int32最后把初始化值从整数字面量改为浮点字面量如ret 0.0验证输出由0变为文档给出的0.6。【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表