稀疏张量基础
稀疏张量基础
稀疏张量是稀疏矩阵的高维扩展,其中非零元素表示为一组索引和关联值。
Data Generation
可以通过提取非零元素直接生成数据。本文展示了一个简单的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)
注意,将坐标与特征一起提取。这是一个简单的示例,效率很低而且是人为的。在许多实际应用中,不太可能获得离散坐标。
稀疏张量初始化
流水线的下一步是初始化稀疏张量。AMinkowskiEngine.SparseTensor需要具有批次索引的坐标;导致张量稀疏D+1 维空间尺寸(如果原始坐标具有 D维 尺寸)。
coords0, feats0 = to_sparse_coo(data_batch_0)
coords1, feats1 = to_sparse_coo(data_batch_1)
coords, feats = ME.utils.sparse_collate(
coords=[coords0, coords1], feats=[feats0, feats1])
这里使用了MinkowskiEngine.utils.sparse_collate函数,但是可以使用MinkowskiEngine.utils.batched_coordinates将坐标列表转换为MinkowskiEngine.SparseTensor兼容坐标。
连续坐标的稀疏张量
在许多情况下,神经网络中使用的坐标是连续的。稀疏张量网络中使用的稀疏张量是在离散坐标系中定义的。要将连续坐标中的特征转换为离散坐标,提供了特征平均功能,可将连续坐标中的特征转换为离散坐标。可以为此简单地使用稀疏张量初始化。例如,
sinput = ME.SparseTensor(
feats=torch.from_numpy(colors), # Convert to a tensor
coords=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)
稀疏张量算法
可以将初始化的稀疏张量与简单的前馈神经网络一起使用,但是在许多情况下,需要执行一些非常规的算子,这就是为什么来使用此库的原因。这里,提供了一些简单的算子,这些算子允许沿特征维的稀疏张量和级联之间的二进制运算。
# sparse tensors
A = ME.SparseTensor(coords=coords, feats=feats)
B = ME.SparseTensor(
coords=new_coords,
feats=new_feats,
coords_manager=A.coords_man, # must share the same coordinate manager
force_creation=True # must force creation since tensor stride [1] exists
)
C = A + B
C = A - B
C = A * B
C = A / B
在这里,创建两个具有不同稀疏模式的稀疏张量。强制第二个稀疏张量B共享坐标管理器coords_man。允许在两个稀疏张量之间共享计算图。目前的语义相当丑陋,但将来会隐藏起来。
如果添加两个稀疏张量,将添加两个功能。如果存在一个非零元素,但在特定坐标上的另一个稀疏张量上没有,将不存在的值设为0,因为稀疏张量仅保存非零元素。根据定义,未指定的任何内容均为0。其他所有二进制算子也是如此。
对于局部算子,强制坐标具有相同的稀疏模式。
# in place operations
# Note that it requires the same coords_key (no need to feed coords)
D = ME.SparseTensor(
# coords=coords, not required
feats=feats,
coords_manager=A.coords_man, # must share the same coordinate manager
coords_key=A.coords_key # For inplace, must share the same coords key
)
A += D
A -= D
A *= D
A /= D
注意,对稀疏张量D使用相同的coords_key。如果尝试使用带有不同coords_key的稀疏张量,将给一个断言错误。
功能串联
如果两个稀疏张量共享相同的coords_key,可以沿特征维连接们。
# If you have two or more sparse tensors with the same coords_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(
coords=[coords0, coords1], feats=[feats0, feats1])
# sparse tensors
A = ME.SparseTensor(coords=coords, feats=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)