稀疏张量基础

稀疏张量是稀疏矩阵的高维扩展,其中非零元素表示为一组索引和相关联的值。 详情请参阅术语表

数据生成

可以直接提取非零元素来生成数据。 在这里,我们展示了一个简单的 2D 数组,中心有 5 个非零元素。

data = [
    [0, 0, 2.1, 0, 0],
    [0, 1, 1.4, 3, 0],
    [0, 0, 4.0, 0, 0]
]

def to_sparse_coo(data):
    # An intuitive way to extract coordinates and features
    coords, feats = [], []
    for i, row in enumerate(data):
        for j, val in enumerate(row):
            if val != 0:
                coords.append([i, j])
                feats.append([val])
    return torch.IntTensor(coords), torch.FloatTensor(feats)

to_sparse_coo(data)

请注意,我们提取坐标和特征。 这是一个简单的例子,效率很低且人为。 在许多实际应用中,您不太可能获得离散化的坐标。 对于有效地量化和提取离散值,请参阅训练演示页面

稀疏张量初始化

流程中的下一步是初始化稀疏张量。 一个 MinkowskiEngine.SparseTensor 需要带有批次索引的坐标; 如果原始坐标有 \(D\) 维度,这会产生一个具有 \(D+1\) 空间维度的稀疏张量。

coords0, feats0 = to_sparse_coo(data_batch_0)
coords1, feats1 = to_sparse_coo(data_batch_1)
coords, feats = ME.utils.sparse_collate(
    coordinates=[coords0, coords1], features=[feats0, feats1])

在这里,我们使用了 MinkowskiEngine.utils.sparse_collate 函数,但你可以使用 MinkowskiEngine.utils.batched_coordinates 将坐标列表转换为 MinkowskiEngine.SparseTensor 兼容的坐标。

连续坐标的稀疏张量

在许多情况下,神经网络中使用的坐标是连续的。 但是,稀疏张量网络中使用的稀疏张量是在离散坐标系中定义的。 为了将连续坐标中的特征转换为离散坐标,我们提供了特征平均函数,可以将连续坐标中的特征转换为离散坐标。 你可以简单地使用稀疏张量初始化来实现。 例如,

sinput = ME.SparseTensor(
    features=torch.from_numpy(colors), # Convert to a tensor
    coordinates=ME.utils.batched_coordinates([coordinates / voxel_size]),  # coordinates must be defined in a integer grid. If the scale
    quantization_mode=ME.SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE  # when used with continuous coordinates, average features in the same coordinate
)
logits = model(sinput).slice(sinput).F

有关更多详细信息,请参阅室内语义分割

稀疏张量算术

你可以使用初始化的稀疏张量和一个简单的正向馈送神经网络,但在许多情况下,你需要进行一些非常规的操作,这就是你使用这个库的原因:) 在这里,我们提供了一些简单的操作,允许稀疏张量之间的二元操作以及沿特征维度的拼接。

# sparse tensors
A = ME.SparseTensor(coordinates=coords, features=feats)
B = ME.SparseTensor(
    coordinates=new_coords,
    features=new_feats,
    coordinate_manager=A.coordinate_manager,  # must share the same coordinate manager
)

C = A + B
C = A - B
C = A * B
C = A / B

在这里,我们创建了两个具有不同稀疏模式的稀疏张量。 但是,我们强制第二个稀疏张量 B 共享 coordinate_manager,一个坐标管理器。 这允许在两个稀疏张量之间共享计算图。 现在语义相当难看,但将来会被隐藏起来。

如果添加两个稀疏张量,这将添加两个特征。 如果存在非零元素,但特定坐标处的另一个稀疏张量上不存在非零元素,我们假设不存在的值为 0,因为稀疏张量仅保存非零元素。 任何我们没有指定的内容,根据定义都是 0。 所有其他二元运算也是如此。

但是,对于原地操作,我们强制坐标具有相同的稀疏模式。

# in place operations
# Note that it requires the same coordinate_map_key (no need to feed coords)
D = ME.SparseTensor(
    # coordinates=coords,  not required
    features=feats,
    coordinate_manager=A.coordinate_manager,  # must share the same coordinate manager
    coordinate_map_key=A.coordinate_map_key  # For inplace, must share the same coords key
)

A += D
A -= D
A *= D
A /= D

请注意,我们对稀疏张量 D 使用相同的 coordinate_map_key。 如果你尝试使用具有不同 coordinate_map_key 的稀疏张量,它会给你一个断言错误。

特征拼接

如果两个稀疏张量共享相同的 coordinate_map_key,则可以沿特征维度拼接它们。

# If you have two or more sparse tensors with the same coordinate_map_key, you can concatenate features
E = ME.cat(A, D)

按批次分解

稀疏张量的内部结构将批次中的所有非零元素折叠成一个坐标矩阵和一个特征矩阵。 为了分解输出,你可以使用一些函数和属性。

coords0, feats0 = to_sparse_coo(data_batch_0)
coords1, feats1 = to_sparse_coo(data_batch_1)
coords, feats = ME.utils.sparse_collate(
    coordinates=[coords0, coords1], features=[feats0, feats1])

# sparse tensors
A = ME.SparseTensor(coordinates=coords, features=feats)
conv = ME.MinkowskiConvolution(
    in_channels=1, out_channels=2, kernel_size=3, stride=2, dimension=2)
B = conv(A)

# Extract features and coordinates per batch index
coords = B.decomposed_coordinates
feats = B.decomposed_features
coords, feats = B.decomposed_coordinates_and_features

# To specify a batch index
batch_index = 1
coords = B.coordinates_at(batch_index)
feats = B.features_at(batch_index)

有关更多信息,请参阅examples/sparse_tensor_basic.py