新闻详情

新闻详情

首页 / 资讯中心 / 详情

Taichi 字段(Field)完全指南:从标量场到结构场的全局数据容器详解

发布时间:2026/9/10 23:48:29来源:尧图网络
Taichi 字段(Field)完全指南:从标量场到结构场的全局数据容器详解
Taichi 字段Field完全指南从标量场到结构场的全局数据容器详解【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi本文以 Taichi 的 Fields 官方文档 为主线系统讲解 Taichi 中“字段field”这一核心全局数据容器的声明、访问与实战用法。无论你是用 Taichi 做物理仿真、图像处理还是科学计算掌握 Scalar / Vector / Matrix / Struct 四类字段的声明方式、索引规则与性能取舍都是写出高效 GPU 内核的前提。读完本文你将能够独立声明并操作从 0D 标量场到多层嵌套结构场在内的任意字段并理解其底层 SNode 布局与编译期展开机制。Field什么是 Taichi 字段Field 一词借用自数学与物理学中的“场”概念——就像你已经熟悉的标量场例如热场或向量场例如引力场一样Taichi 中的字段是全局数据容器它既可以在 Python 作用域访问也可以在 Taichi 内核kernel作用域访问。类比起来最容易理解就像 NumPy 中的 ndarray 或 PyTorch 中的 tensor一个字段被定义为多维元素数组字段中的每个元素可以是标量Scalar、向量Vector、矩阵Matrix或结构体Struct。从源码结构看ti.field的入口定义位于 python/taichi/lang/impl.py其文档字符串明确说明“A Taichi field can be viewed as an abstract N-dimensional array, hiding away the complexity of how its underlying SNode are actually defined”——字段本质上是底层 SNodeScattered Node层级结构的抽象封装数据既可由 Python 直接访问也可被 Taichi kernel 直接读写。标量字段Scalar Fields标量字段是存储标量的字段也是最基础的字段类型0D 标量字段单个标量1D 标量字段一维标量数组2D 标量字段二维标量数组以此类推。声明标量字段声明标量字段最简单的方式是调用ti.field(dtype, shape)其中dtype是基本数据类型参见 Type System类型系统 中的说明shape是整数元组。声明 0D 标量字段时需要把 shape 设为空元组()# 声明一个数据类型为 f32 的 0D 标量字段 f_0d ti.field(ti.f32, shape()) # 0D 字段f_0d的布局示意┌─────┐ │ │ └─────┘ └─────┘ f_0d.shape()声明长度为n的 1D 标量字段将 shape 设为n或(n,)f_1d ti.field(ti.i32, shape9) # 长度为 9 的 1D 字段f_1d的布局示意┌───┬───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┴───┘ └───────────────────────────────────┘ f_1d.shape (9,)这里有一个容易踩坑的细节0D 字段与长度为 1 的 1D 字段只有索引规则不同。访问 0D 字段必须用None作为索引而访问长度为 1 的 1D 字段用0f1 ti.field(int, shape()) f2 ti.field(int, shape1) f1[None] 1 # 访问 0D 字段用 None f2[0] 1 # 访问长度为 1 的 1D 字段用 0声明 2D 标量字段时需要分别指定两个维度行数和列数。例如下面这段代码定义了一个 shape 为(3, 6)的 2D 标量字段3 行 6 列f_2d ti.field(int, shape(3, 6)) # 一个 shape 为 (3, 6) 的 2D 字段f_2d的布局示意f_2d.shape[1] (6) ┌───────────────────────┐ ┌ ┌───┬───┬───┬───┬───┬───┐ ┐ │ │ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┤ │ f_2d.shape[0] │ │ │ │ │ │ │ │ │ (3) │ ├───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ │ │ └ └───┴───┴───┴───┴───┴───┘ ┘更高维度的标量字段可以依此类推地声明。:::caution WARNINGTaichi 仅支持维度 ≤ 8 的字段。:::实现层面Taichi 后台为字段索引数量预留了上限taichi_max_num_indices定义在 taichi/inc/constants.h而 Python 层的字段按文档约定将可用维度限制在 8 以内。访问标量字段中的元素字段一旦声明Taichi 会自动将其所有元素初始化为零。要访问标量字段中的某个元素需要显式指定其索引。:::note 访问 0D 字段x时请写x[None] 0不要写x 0。 :::访问 0D 字段即使字段只有一个元素也必须使用索引Nonef_0d ti.field(ti.f32, shape()) f_0d[None] 10.0f_0d的布局┌──────┐ │ 10.0 │ └──────┘ └──────┘ f_0d.shape()访问 1D 字段用索引i获取第i个元素f_1d ti.field(ti.f32, shape(9,)) ti.kernel def loop_over_1d(): for i in range(9): f_1d[i] i loop_over_1d()执行后f_1d的布局┌───┬───┬───┬───┬───┬───┬───┬───┬───┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ └───┴───┴───┴───┴───┴───┴───┴───┴───┘访问 2D 字段用整数对(i, j)获取第i行第j列的元素。Taichi 还支持直接在for循环中遍历字段的所有索引f_2d ti.field(ti.f32, shape(16, 16)) ti.kernel def loop_over_2d(): for i, j in f_2d: f_2d[i, j] i loop_over_2d()执行后f_2d的布局每行元素等于其行号┌───┬───┬───┬───┬───┬───┐ │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ ├───┼───┼───┼───┼───┼───┤ │ 1 │ 1 │ 1 │ 1 │ 1 │ 1 │ ├───┼───┼───┼───┼───┼───┤ │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ └───┴───┴───┴───┴───┴───┘访问 n 维字段用整数 n 元组(i, j, k, ...)作为索引。实战示例用 2D 标量场表示灰度图像你可以用 2D 标量字段表示二维数值网格。下面这段代码创建并显示一幅 640×480 的随机灰度图import taichi as ti ti.init(archti.cpu) width, height 640,480 # 创建一个 640x480 的标量字段每个元素代表一个像素值f32 gray_scale_image ti.field(dtypeti.f32, shape(width, height)) ti.kernel def fill_image(): # 用随机灰度填充图像 for i,j in gray_scale_image: gray_scale_image[i,j] ti.random() fill_image() # 创建与灰度图同尺寸的 GUI gui ti.GUI(gray-scale image of random values, (width, height)) while gui.running: gui.set_image(gray_scale_image) gui.show()这段代码完整展示了字段的典型用法声明 2D 字段 → 在ti.kernel中遍历字段所有索引并写入ti.random()→ 通过ti.GUI实时渲染。:::caution WARNINGTaichi 字段不支持切片slicing。以下两种用法都是错误的for x in f_2d[0]: # 错误试图访问第一行但不受支持 ...f_2d[0][3:] [4, 5, 6] # 错误试图访问第一行的切片但不受支持无论哪种写法系统都会抛出错误信息 Slicing is not supported on ti.field。:::实现层面在 python/taichi/lang/field.py 的ScalarField.__getitem__中Python 作用域访问会逐一检查索引类型非int/np.integer类型的索引例如切片对象会抛出TypeError: ... slicing a ti.field is not supported so far与文档中的报错信息一致。用给定值填充标量字段要将标量字段的所有元素设置为给定值调用field.fill()x ti.field(int, shape(5, 5)) x.fill(1) # 将 x 中所有元素设为 1 ti.kernel def test(): x.fill(-1) # 在内核中把 x 中所有元素设为 -1注意fill()既可以在 Python 作用域调用也可以在ti.kernel内核内部调用。从实现看python/taichi/lang/field.pyPython 作用域走taichi._kernels中的fill_field内核Taichi 作用域则走taichi._funcs中的field_fill_taichi_scope两条路径都会正确广播填充值。字段元数据元数据提供标量字段的基本信息通过shape和dtype属性即可获取数据类型与形状f_1d.shape # (9,) f_3d.dtype # f32实现层面Field基类python/taichi/lang/field.py中shape与dtype都是只读属性分别代理到代表性 SNode 的shape与_dtype因此任何子类标量/向量/矩阵/结构字段都统一暴露这两个属性。向量字段Vector Fields顾名思义向量字段是元素为向量的字段。向量代表什么取决于程序的场景——例如像素的 (R, G, B) 三元组、粒子的位置、空间中的引力场等等。声明向量字段声明向量字段与声明标量字段类似区别在于需要调用ti.Vector.field而非ti.field并将向量维度N作为第一个位置参数传入。例如下面这段代码声明了一个 3×3 的 2D 向量字段每个元素是 2D 向量# 声明一个由 2D 向量组成的 3x3 向量字段 f ti.Vector.field(n2, dtypefloat, shape(3, 3))f的布局示意f.shape[1] (3) ┌────────────────────┐ ┌ ┌──────┬──────┬──────┐ ┐ │ │[*, *]│[*, *]│[*, *]│ │ │ ├──────┼──────┼──────┤ │ f.shape[0] │ │[*, *]│[*, *]│[*, *]│ │ [*, *] (3) │ ├──────┼──────┼──────┤ │ └─────┘ │ │[*, *]│[*, *]│[*, *]│ │ n2 └ └──────┴──────┴──────┘ ┘下面这段代码声明了一个300x300x300的向量字段volumetric_field向量维度为 4常用于体数据如速度场、标量场可视化box_size (300, 300, 300) # 3D 空间中的 300x300x300 网格 # 声明一个 300x300x300 的向量字段向量维度 n4 volumetric_field ti.Vector.field(n4, dtypeti.f32, shapebox_size)实现层面ti.Vector.field是ti.Matrix.field的特例。在 python/taichi/lang/matrix.py 中Vector.field(n, dtype, ...)实际调用Matrix.field(n, 1, dtype, ..., ndim1)即把向量视为只有一列的矩阵。此外ti.field入口python/taichi/lang/impl.py在检测到 dtype 为 1 维MatrixType时也会自动分派到Vector.field。访问向量字段中的元素访问向量字段与访问多维数组类似用索引运算符[]访问字段中的元素。唯一区别是要访问某个元素向量的具体分量需要额外再加一个索引运算符[]访问上述体数据场中某一位置的速度向量volumetric_field[i, j, k]访问该速度向量的第l个分量volumetric_field[i, j, k][l]:::note 当向量维度不超过 4 时还可以用xyzw或rgba这类 swizzling 索引访问向量分量volumetric_field[i, j, k].x 1 # 等价于 volumetric_field[i, j, k][0] 1 volumetric_field[i, j, k].y 2 # 等价于 volumetric_field[i, j, k][1] 2 volumetric_field[i, j, k].z 3 # 等价于 volumetric_field[i, j, k][2] 3 volumetric_field[i, j, k].w 4 # 等价于 volumetric_field[i, j, k][3] 4 volumetric_field[i, j, k].xyz 1, 2, 3 # 将 1, 2, 3 赋给前三个分量 volumetric_field[i, j, k].rgb 1, 2, 3 # 与上式等价:::下面的代码生成并打印一个随机向量场。注意内层循环使用了ti.static(range(n))让编译器在编译期展开循环# n: 向量维度; w: 宽度; h: 高度 n, w, h 3, 128, 64 vec_field ti.Vector.field(n, dtypefloat, shape(w,h)) ti.kernel def fill_vector(): for i,j in vec_field: for k in ti.static(range(n)): # ti.static 展开内层循环 vec_field[i,j][k] ti.random() fill_vector() print(vec_field[w-1,h-1][n-1]):::note 访问 0D 向量字段x ti.Vector.field(n3, dtypeti.f32, shape())的第p个分量时需要写成x[None][p]其中 0 ≤ p n。 :::矩阵字段Matrix Fields顾名思义矩阵字段是元素为矩阵的字段。在连续介质力学中3D 材料中每个无限小点上都存在应变张量和应力张量例如一个 3×2 矩阵就可以用矩阵字段来表示。声明矩阵字段下面这段代码声明了一个张量场# 声明一个 300x400x500 的矩阵字段每个元素是 3x2 矩阵 tensor_field ti.Matrix.field(n3, m2, dtypeti.f32, shape(300, 400, 500))访问矩阵字段中的元素访问矩阵字段与访问向量字段类似用第一个索引运算符[]做字段索引再用第二个索引运算符[]做矩阵索引。访问矩阵字段tensor_field的第i, j个元素mat tensor_field[i, j]访问元素mat中第一行第二列的分量mat[0, 1]或tensor_field[i, j][0, 1]:::note 访问 0D 矩阵字段x ti.Matrix.field(n3, m4, dtypeti.f32, shape())时需要写成x[None][p, q]其中 0 ≤ p n0 ≤ q m。 :::注意事项矩阵尺寸矩阵运算会在编译期全部展开unrolled。看下面的例子import taichi as ti ti.init() a ti.Matrix.field(n2, m3, dtypeti.f32, shape(2, 2)) ti.kernel def test(): for i in ti.grouped(a): # a[i] 是一个 2x3 矩阵 a[i] [[1, 1, 1], [1, 1, 1]] # 该赋值在编译期被展开为 # a[i][0, 0] 1 # a[i][0, 1] 1 # a[i][0, 2] 1 # a[i][1, 0] 1 # a[i][1, 1] 1 # a[i][1, 2] 1操作过大的矩阵例如32x128会导致更长的编译时间和较差的性能。出于性能考虑建议保持矩阵较小2x1、3x3、4x4这类矩阵完全没问题32x6就有点偏大了。变通方案声明矩阵字段时把大的维度留给字段field而不是留给矩阵。如果你需要的是一个3x2的字段里面每个元素是64x32的矩阵不推荐ti.Matrix.field(64, 32, dtypeti.f32, shape(3, 2))推荐ti.Matrix.field(3, 2, dtypeti.f32, shape(64, 32))实现层面Matrix.field的完整签名在 python/taichi/lang/matrix.py除了n行数、m列数、dtype、shape还支持order内存布局顺序、offset索引偏移、needs_grad/needs_dual自动微分梯度场以及layoutAOS 或 SOA 布局。每个n x m矩阵在底层被拆解为n * m个独立字段成员matrix.py这正是矩阵运算需要编译期展开的根本原因——矩阵越大展开的成员和指令越多编译与运行开销也越大。结构字段Struct Fields结构字段是存储用户自定义结构体的字段。结构体元素的成员可以是标量Scalar向量Vector矩阵Matrix其他结构体字段声明结构字段下面这段代码使用ti.Struct.field()声明一个包含粒子信息位置、速度、加速度、质量的 1D 字段。注意成员变量pos、vel、acc、mass以字典格式提供可以使用复合类型compound types如ti.types.vector、ti.types.matrix、ti.types.struct来把向量、矩阵或结构体声明为结构体成员参见 Type System 中的复合类型。# 使用 ti.Struct.field() 方法声明一个 1D 结构字段 n 10 particle_field ti.Struct.field({ pos: ti.math.vec3, vel: ti.math.vec3, acc: ti.math.vec3, mass: float, }, shape(n,))除了直接使用ti.Struct.field()也可以先声明一个复合类型particle再创建该类型的字段# vec3 是 taichi.math 模块提供的内置向量类型 vec3 ti.math.vec3 n 10 # 声明一个包含三个向量和一个浮点数的结构体 particle ti.types.struct( posvec3, velvec3, accvec3, massfloat, ) # 调用 field() 声明一个由结构体 particle 组成的 1D 字段 particle_field particle.field(shape(n,))访问结构字段中的元素访问结构字段中某个元素的成员有两种方式索引优先index-first或名称优先name-first。索引优先先用索引定位某个元素再指定目标成员的名字# 将字段中第一个粒子的位置设为 [0.0, 0.0, 0.0] particle_field[0].pos vec3(0) # particle_field 是 1D 结构字段pos 是 3D 向量名称优先先创建一个“子字段”它聚合了结构字段中所有mass成员然后用索引运算符[]访问具体成员particle_field.mass[0] 1.0 # 将字段中第一个粒子的质量设为 1.0由于particle_field.mass本质上是一个由particle_field中所有mass成员组成的字段你还可以对它整体调用fill()一次性把成员设为特定值particle_field.mass.fill(1.0) # 将结构字段中所有粒子的质量设为 1.0实现层面Struct.field在 python/taichi/lang/struct.py 中实现。每个成员标量/向量/矩阵/嵌套结构体都会被递归地创建为独立的Field实例再统一按layout参数Layout.AOS结构体数组 /Layout.SOA数组结构体放置到底层 SNode 树中struct.py。StructField通过_register_fields把成员注册为自身属性struct.py这正是particle_field.mass这种“名称优先”访问得以实现的机制而fill()则会递归地对每个成员字段调用各自的fillstruct.py。从源码理解字段的设计与边界结合 python/taichi/lang/impl.py 中ti.field的完整签名可以看到字段声明还支持以下常用参数它们在原文档基础上进一步扩展了字段的表达能力参数含义说明dtype数据类型可以是标量类型也可以是ti.math.vec3等向量/矩阵类型会自动分派到对应 field 构造器shape字段形状整数或整数元组维度 ≤ 8order内存布局顺序例如ji表示第二维在外层影响遍历时的缓存局部性offset索引偏移例如offset(-10, -10)让字段索引从(-10, -10)而非(0, 0)开始适用于带负坐标的仿真域needs_grad反向模式自动微分为字段生成伴随梯度场needs_dual前向模式自动微分为字段生成对偶梯度场layout布局模式AOS结构体数组或 SOA数组结构体对向量/矩阵/结构字段有效同时Field基类python/taichi/lang/field.py还提供了一套与外部生态互操作的方法包括to_numpy()/from_numpy()、to_torch()/from_torch()、to_paddle()/from_paddle()以及copy_from()方便字段与 NumPy / PyTorch / Paddle 数据在 Python 与 Taichi 之间双向搬运。例如ScalarField.to_numpy在 field.py 中通过预分配的np.zeros加tensor_to_ext_arr内核实现。在实际项目中字段的声明与访问贯穿于所有测试用例例如 tests/python/test_fill.py 与 tests/python/bls_test_template.py 中大量使用了ti.field(ti.i32)、ti.field(dtype..., shape..., needs_gradTrue)等声明模式读者可以结合这些测试进一步验证本文介绍的各种用法。小结本文以四类字段为线索完整覆盖了 Taichi 字段体系的核心用法标量字段ti.field(dtype, shape)声明x[None]/x[i]/x[i, j]索引访问fill()批量填充shape/dtype元数据查询维度上限为 8且不支持切片向量字段ti.Vector.field(n, dtype, shape)声明双重索引field[i, j][k]或 swizzlingxyzw/rgba访问分量矩阵字段ti.Matrix.field(n, m, dtype, shape)声明注意矩阵尺寸会带来编译期展开开销尽量把大维度留给字段而非矩阵结构字段ti.Struct.field({...}, shape...)或ti.types.struct(...).field(...)声明支持索引优先与名称优先两种访问方式成员可嵌套。掌握这四类字段你就能在 Python 与 Taichi 内核之间自由地组织、读写多维数据为后续学习 kernel 编写、自动微分与 SNode 布局优化打下坚实基础。【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Docker镜像导入与运行全流程实践指南 2026/9/11 0:21:32

Docker镜像导入与运行全流程实践指南

1. Docker镜像导入与运行的核心价值在现代化开发运维体系中,Docker已经成为应用部署的标准工具。作为从业五年的全栈开发者,我深刻体会到镜像管理是Docker技术栈中最基础却最容易出问题的环节。特别是在团队协作、跨环境部署时,如何正确导入和…

阅读更多 →
Python生成器:从基础原理到高效内存管理实战 2026/9/11 0:21:32

Python生成器:从基础原理到高效内存管理实战

1. 生成器是什么?从迭代器说起 第一次听说Python生成器时,我正被一个内存问题困扰着——需要处理一个几十GB的日志文件,但我的笔记本只有16GB内存。传统方法是将整个文件读入内存,这显然行不通。直到同事扔给我一个yield关键字&am…

阅读更多 →
SSM框架开发微信校园订餐小程序实战解析 2026/9/11 0:21:32

SSM框架开发微信校园订餐小程序实战解析

1. 项目背景与核心功能解析"weixin248食堂订餐小程序"是一个基于SSM框架开发的微信校园应用解决方案。这类项目在高校信息化建设中具有典型意义——根据2023年教育后勤协会数据,全国已有67%的高校食堂采用线上订餐系统。与市面上通用外卖平台不同&#xf…

阅读更多 →
Spring Integration与MQTT协议整合实践与优化 2026/9/11 0:21:32

Spring Integration与MQTT协议整合实践与优化

1. Spring Integration与MQTT协议整合概述在企业级应用开发中,系统集成是一个永恒的话题。最近我在一个物联网项目中尝试将Spring Integration与MQTT协议结合使用,发现这种组合能优雅地解决设备与后端系统的异步通信问题。MQTT作为一种轻量级的发布/订阅…

阅读更多 →
多站融合储能电站MATLAB建模与优化实践 2026/9/11 0:21:32

多站融合储能电站MATLAB建模与优化实践

1. 多站融合储能电站的行业背景与挑战 在新型电力系统建设背景下,多站融合已成为能源互联网发展的重要方向。所谓多站融合,是指将变电站、储能电站、数据中心站、5G基站等不同功能站点进行物理整合和系统协同,实现资源集约化利用和能源高效管…

阅读更多 →
9Router 接入 VSCode Continue:在本地 AI 编程助手中解锁 40+ 免费与订阅大模型 2026/9/11 0:18:32

9Router 接入 VSCode Continue:在本地 AI 编程助手中解锁 40+ 免费与订阅大模型

9Router 接入 VSCode Continue:在本地 AI 编程助手中解锁 40 免费与订阅大模型 【免费下载链接】9router Unlimited FREE AI coding. Connect Claude Code, Codex, Cursor, Cline, Copilot, Antigravity to FREE Claude/GPT/Gemini via 40 providers. Auto-fallback…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞