Rerun TensorDimensionIndexSelection 类型详解:张量维度精确定位与切片选择机制
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
TensorDimensionIndexSelection是 Rerun 数据模型中的一个稳定(stable)编码(encoding)类型,用于在张量(tensor)中精确定位某一具体维度上的某一个索引,是 Tensor 视图按 2D 切片展示 N 维数据时的核心基础。本文以官方参考文档为主线,结合仓库内类型定义源码、SDK 绑定与 Tensor 视图实现,完整讲解该类型的字段语义、Arrow 内存表示、各语言 SDK 中的使用方式,以及在蓝图(Blueprint)切片选择中的实际应用与边界校正规则。
类型概览:用"维度号 + 索引"定位张量中的一"页"
官方参考文档(docs/content/reference/types/encodings/tensor_dimension_index_selection.md)对它的定义只有一句话:对某个张量维度进行索引(Indexing a specific tensor dimension)。它不直接描述一个切片或区间,而是描述"在哪个维度的第几个位置取值",从而把 N 维张量"压扁"到可展示的 2D 平面。
该编码只包含两个非空(non-null)字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
dimension | 非空UInt32 | 要选择的维度编号(0 起始) |
index | 非空UInt64 | 在该维度上使用的索引值 |
例如选择dimension=2且index=42,等价于在 NumPy 中执行tensor[:, :, 42, :, :, …]——即第 2 维固定取第 42 个切片,其余维度保持完整。
语义本质:与 NumPy 索引的一一对应
官方文档用 NumPy 语法来解释该类型的行为,这是理解其设计意图最直观的方式。设有一个 5 维张量tensor,形状为(A, B, C, D, E):
- 一个
TensorDimensionIndexSelection(dimension=2, index=42)表示tensor[:, :, 42, :, :],结果形状为(A, B, D, E); - 多个
TensorDimensionIndexSelection组合使用时,每一个都会把对应维度"固定"为一个标量索引,最终剩下来的维度构成可渲染的 2D 图像或曲线。
这一语义贯穿 Rerun 的 Tensor 视图:N 维数据(例如视频帧序列、多通道特征图、体素数据)必须选择两个维度映射为图像的宽高(width/height),其余所有维度则各取一个索引值才能得到确定的一张"切片"。TensorDimensionIndexSelection正是承担"其余维度各取一值"这个职责的数据结构。
类型定义与代码生成链路
该类型不是手写代码,而是由 Rerun 的类型定义文件驱动生成。权威定义位于类型定义源文件 crates/build/re_type_definitions/rerun/encodings/tensor_dimension_selection.def.rs:
/// Indexing a specific tensor dimension. /// /// Selecting `dimension=2` and `index=42` is similar to doing `tensor[:, :, 42, :, :, …]` in numpy. #[rerun::rerun_type] #[rust(derive(Default, Copy, Hash, PartialEq, Eq))] #[rerun(state = "stable")] pub struct TensorDimensionIndexSelection { /// The dimension number to select. pub dimension: u32, /// The index along the dimension to use. pub index: u64, }值得注意的细节:
- 标记
state = "stable",说明该类型已处于稳定状态,SDK 各语言绑定保持同步; - 该文件同一处还定义了
TensorDimensionSelection(含invert: bool,用于宽高维度的翻转),两者职责不同:Selection描述"维度的方向/选择",而IndexSelection描述"维度上的具体下标"; re_types_builder会根据这份定义自动生成 Rust、Python、C++ 三端绑定。
Rust 实现:结构与 Arrow 序列化
Rust 侧生成的编码结构位于 crates/store/re_sdk_types/src/encodings/tensor_dimension_index_selection.rs,与文档完全一致:
pub struct TensorDimensionIndexSelection { pub dimension: u32, pub index: u64, }它派生Clone, Debug, Default, Copy, Hash, PartialEq, Eq以及SizeBytes,是一个轻量、可拷贝的值类型,可嵌入蓝图组件批量传输。
Arrow 数据类型的落地
文档中给出了该编码的 Arrow datatype 声明:
Struct( "dimension": non-null UInt32 "index": non-null UInt64 )在 Rust 源码中,ArrowDataType实现直接对应这一声明(crates/store/re_sdk_types/src/encodings/tensor_dimension_index_selection.rs#L41-L50):
impl ::re_types_core::ArrowDataType for TensorDimensionIndexSelection { fn arrow_data_type() -> arrow::datatypes::DataType { DataType::Struct(Fields::from(vec![ Field::new("dimension", DataType::UInt32, false), Field::new("index", DataType::UInt64, false), ])) } }其中Field::new(..., false)的第三个参数即nullable = false,印证了文档中"非空"的约束。to_arrow序列化时会将一批(batch)TensorDimensionIndexSelection拆成两个独立的PrimitiveArray(UInt32Array+UInt64Array)再合并为StructArray;from_arrow反序列化则按字段名查找子数组,缺失字段会返回missing_struct_field错误(见 同文件 L125-L207)。由于两个字段均声明非空,反序列化入口还调用err_on_nulls对整体做空值检查,保证数据完整性。
Python 绑定:attrs 数据类
Python SDK 的对应类在 rerun_py/rerun_sdk/rerun/encodings/tensor_dimension_index_selection.py,由代码生成器产出、基于attrs:
@define(init=False) class TensorDimensionIndexSelection: def __init__(self, dimension: int, index: int) -> None: self.__attrs_init__(dimension=dimension, index=index) dimension: int = field(converter=int) # 要选择的维度编号 index: int = field(converter=int) # 该维度上使用的索引字段均带converter=int,传入可转换为整型的值会被自动归一化。模块同时导出TensorDimensionIndexSelectionArrayLike、TensorDimensionIndexSelectionBatch等批量类型别名,便于直接构造数组输入蓝图组件(见同文件__all__)。
组件包装:从编码到蓝图组件
TensorDimensionIndexSelection编码本身不直接出现在日志 API 中,而是被包装成同名组件(Component)供蓝图使用。包装定义在 crates/store/re_sdk_types/src/components/tensor_dimension_index_selection.rs:
#[repr(transparent)] pub struct TensorDimensionIndexSelection(pub crate::encodings::TensorDimensionIndexSelection); impl ::re_types_core::WrapperComponent for TensorDimensionIndexSelection { type Encoding = crate::encodings::TensorDimensionIndexSelection; fn name() -> ComponentType { "rerun.components.TensorDimensionIndexSelection".into() } }#[repr(transparent)]使组件与编码内存布局完全一致,零开销包装;- 组件全名为
rerun.components.TensorDimensionIndexSelection,与参考文档中"Used by"小节指向的组件文档(docs/content/reference/types/components/tensor_dimension_index_selection.md)一一对应; - 便捷构造方法由扩展文件提供(crates/store/re_sdk_types/src/components/tensor_dimension_index_selection_ext.rs):
TensorDimensionIndexSelection::new(dimension: u32, index: u64)。
实际应用场景:TensorSliceSelection 蓝图
该组件最核心的消费方是蓝图 archetypeTensorSliceSelection(2D 张量切片选择),其类型定义见 crates/build/re_type_definitions/rerun/blueprint/archetypes/tensor_slice_selection.def.rs:
pub struct TensorSliceSelection { /// Which dimension to map to width. pub width: Option<rerun::components::TensorWidthDimension>, /// Which dimension to map to height. pub height: Option<rerun::components::TensorHeightDimension>, /// Selected indices for all other dimensions. pub indices: Option<Vec<rerun::components::TensorDimensionIndexSelection>>, /// Any dimension listed here will have a slider for the index. pub slider: Option<Vec<rerun::blueprint::components::TensorDimensionIndexSlider>>, }分工非常清晰:
width/height决定哪两个维度映射为图像的宽和高;indices中的每个TensorDimensionIndexSelection负责"其余维度"各取一个具体下标;slider决定哪些维度提供索引滑条,滑条编辑会直接改写indices列表中的对应项;- 若某个
indices中的维度恰好等于width或height,该条目会被忽略。
Python 侧对应类在 rerun_py/rerun_sdk/rerun/blueprint/archetypes/tensor_slice_selection.py,构造参数同样为width、height、indices、slider,其中indices类型为encodings.TensorDimensionIndexSelectionArrayLike。
一个典型的 Python 用法示例
import rerun as rr import rerun.blueprint as rrb # 对形状为 (frame, width, height, channel) 的数据: # 将 width/height 映射为图像宽高,frame 固定在 12,channel 固定在 0 slice_selection = rrb.archetypes.TensorSliceSelection( width=rrb.components.TensorWidthDimension(dimension=1), height=rrb.components.TensorHeightDimension(dimension=2), indices=[ rr.encodings.TensorDimensionIndexSelection(dimension=0, index=12), rr.encodings.TensorDimensionIndexSelection(dimension=3, index=0), ], )这样 Tensor 视图就会在交互中只展示"第 12 帧、通道 0"这一张 2D 切片。
视图侧的边界校正:越界裁剪与默认中间索引
仅声明indices还不够,因为用户配置的维度号或索引值可能超出张量实际形状。Tensor 视图在加载蓝图后会对切片选择做"清洗"(scrub),核心逻辑在 crates/views/re_view_tensor/src/dimension_mapping.rs 的load_and_make_valid,规则如下:
- 越界维度被剔除:
index.dimension >= shape.len()的条目直接retain过滤掉;与width/height冲突的条目同样被移除(L142-L146); - 越界索引被裁剪:
index被at_most(size - 1)钳制到合法范围(L149-L157); - 未被覆盖的维度自动补中间值:对没有出现在任何选择中的维度,自动填入
index = size / 2,保证最终一定得到一个完整的 2D 切片(L159-L170)。
这些规则都有单元测试背书,见 dimension_mapping.rs 测试模块:例如对形状(100, 200, 300)的张量,index=1000会被分别裁剪为99/199/299;维度 0、1 若被宽高占用,则只保留维度 2 的索引选择。
交互层:拖拽与滑条如何写回 indices
在查看器界面中,Tensor 视图的"Image / Selectors"面板允许用户拖拽维度到宽高槽位,并通过眼睛图标开关某维度的滑条(crates/views/re_view_tensor/src/tensor_dimension_mapper.rs):
- 把某个维度拖入已有 Selector 时,会替换该位置的
TensorDimensionIndexSelection并默认开启滑条(L81-L101); - 拖动宽高槽位到 Selector 时,会以该维度中间索引(
size / 2)作为固定值生成新选择(L31-L42); - 切换滑条可见性时,会同步增删
slider组件列表(L259-L277)。
由此可见,TensorDimensionIndexSelection既是蓝图中的静态配置数据,也是查看器交互操作实时回写目标的载体——这正是文档用"Indexing a specific tensor dimension"概括它的深层含义。
小结
TensorDimensionIndexSelection虽然只有两个字段,却是 Rerun 把任意 N 维张量映射为 2D 可视切片的基石:
- 语义简单:
dimension+index即 NumPy 的tensor[:, :, idx, :, ...]; - 表示稳定:固定为
Struct(UInt32, UInt64)的非空 Arrow 结构,跨 Rust/Python/C++ 三端 SDK 一致; - 应用明确:作为
TensorSliceSelection蓝图的indices组件,决定宽高之外所有维度的取值,并在视图侧完成越界清洗与默认值填充。
如需深入,可直接阅读上述源码与测试文件,或参考同目录下的组件参考文档 docs/content/reference/types/components/tensor_dimension_index_selection.md 了解其作为组件的完整语义。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考