2021SC@SDUSC
open3d
Open3D ML是Open3D的一个扩展,用于3D机器学习任务。它建立在Open3D核心库的基础上,并使用机器学习工具对其进行扩展,以进行3D数据处理。要使用它,需要使用PyTorch或TensorFlow安装Open3D,并查看Open3D-ML。
后面将对与Open3D-ML相关的python-open3d-ml-tf-python-layers中的代码进行分析
convolutions.py
from ...python.ops import ops
from .neighbor_search import FixedRadiusSearch, RadiusSearch
import tensorflow as tf
import numpy as np
__all__ = ['ContinuousConv', 'SparseConv', 'SparseConvTranspose']
class ContinuousConv(tf.keras.layers.Layer):
连续卷积。这种卷积支持连续的输入和输出点位置。此层实现中定义的卷积
位置:math:`\mathbf x`处的卷积定义为(f*g)(\mathbf x) = \frac{1}{\psi(\mathbf x)} \sum_{i \in \mathcal N(\mathbf x, R)} a(\mathbf x_i, \mathbf x)\; f_i\; g(\Lambda(\mathbf x_i - \mathbf x)).
使用:math:`f`作为输入特征函数,使用:math:`g`作为过滤函数。
输入点是:math:`\mathbf x_i`,输入特性是:math:`f_i`。
规范化:math:`\frac{1}{\psi(\mathbf x)}`可以使用**normalize**参数打开。
每邻居值:math:`a(\mathbf x\u i,\mathbf x)`可用于实现窗口函数;以及参见参数**window_function**。
用于查找过滤器值的函数:math:`\Lambda`由参数**coordinate_mapping**坐标映射和**interpolation**插值定义。
offset = self.offset
if inp_importance is None:
inp_importance = tf.ones((0,), dtype=tf.float32)
extents = tf.convert_to_tensor(extents)
return_distances = not self.window_function is None
if not user_neighbors_index is None and not user_neighbors_row_splits is None:
if user_neighbors_importance is None:
neighbors_importance = tf.ones((0,), dtype=tf.float32)
else:
neighbors_importance = user_neighbors_importance
neighbors_index = user_neighbors_index
neighbors_row_splits = user_neighbors_row_splits
else:
if extents.shape.rank == 0:
radius = 0.5 * extents
self.nns = self.fixed_radius_search(
inp_positions,
queries=out_positions,
radius=radius,
hash_table=fixed_radius_search_hash_table)
if return_distances:
if self.radius_search_metric == 'L2':
neighbors_distance_normalized = self.nns.neighbors_distance / (
radius * radius)
else: # L1
neighbors_distance_normalized = self.nns.neighbors_distance / radius
elif extents.shape.rank == 1:
radii = 0.5 * extents
self.nns = self.radius_search(inp_positions,
queries=out_positions,
radii=radii)
else:
raise Exception("extents rank must be 0 or 1")
if self.window_function is None:
neighbors_importance = tf.ones((0,), dtype=tf.float32)
else:
neighbors_importance = self.window_function(
neighbors_distance_normalized)
neighbors_index = self.nns.neighbors_index
neighbors_row_splits = self.nns.neighbors_row_splits
该函数用于计算输出特征。
num_pairs = tf.shape(neighbors_index)[0]
self._avg_neighbors = tf.dtypes.cast(
num_pairs, tf.float32) / tf.dtypes.cast(
tf.shape(out_positions)[0], tf.float32)
extents_rank2 = extents
while extents_rank2.shape.rank < 2:
extents_rank2 = tf.expand_dims(extents_rank2, axis=-1)
self._conv_values = {
'filters': self.kernel,
'out_positions': out_positions,
'extents': extents_rank2,
'offset': offset,
'inp_positions': inp_positions,
'inp_features': inp_features,
'inp_importance': inp_importance,
'neighbors_index': neighbors_index,
'neighbors_row_splits': neighbors_row_splits,
'neighbors_importance': neighbors_importance,
'align_corners': self.align_corners,
'coordinate_mapping': self.coordinate_mapping,
'interpolation': self.interpolation,
'normalize': self.normalize,
}
out_features = ops.continuous_conv(**self._conv_values)
self._conv_output = out_features
if self.use_dense_layer_for_center:
self._dense_output = self.dense(inp_features)
out_features = out_features + self._dense_output
if self.use_bias:
out_features += self.bias
out_features = self.activation(out_features)
return out_features
def compute_output_shape(self, inp_features_shape):
return tf.TensorShape((None, self.filters))
统计和调试。
class SparseConv(tf.keras.layers.Layer):
稀疏卷积。该层计算仅在指定输出位置计算的卷积。该层假定输入和输出点位于规则网格上。
offset = self.offset
voxel_size = tf.convert_to_tensor(voxel_size, dtype=inp_positions.dtype)
if voxel_size.shape.rank != 0:
raise Exception("voxel_size must be a scalar")
if inp_importance is None:
inp_importance = tf.ones((0,), dtype=tf.float32)
if isinstance(inp_features, tf.RaggedTensor):
if not (isinstance(inp_positions, tf.RaggedTensor) and
isinstance(out_positions, tf.RaggedTensor)):
raise Exception(
"All of inp_positions, inp_features and out_positions must be tf.Tensor, or tf.RaggedTensor"
)
hash_table_size_factor = 1 / 64
self.nns = self.fixed_radius_search(
inp_positions,
queries=out_positions - offset * voxel_size,
radius=self.kernel_size[0] * voxel_size * 0.51,
hash_table_size_factor=hash_table_size_factor,
hash_table=fixed_radius_search_hash_table)
out_positions_split = None
if isinstance(inp_positions, tf.RaggedTensor):
inp_positions = inp_positions.values
inp_features = inp_features.values
out_positions_split = out_positions.row_splits
out_positions = out_positions.values
num_pairs = tf.shape(self.nns.neighbors_index)[0]
self._avg_neighbors = num_pairs / tf.shape(out_positions)[0]
extents_rank2 = tf.fill([1, 1], voxel_size * self.kernel_size[0])
self._conv_values = {
'filters': self.kernel,
'out_positions': out_positions,
'extents': extents_rank2,
'offset': offset,
'inp_positions': inp_positions,
'inp_features': inp_features,
'inp_importance': inp_importance,
'neighbors_index': self.nns.neighbors_index,
'neighbors_importance': tf.ones((0,), dtype=tf.float32),
'neighbors_row_splits': self.nns.neighbors_row_splits,
'align_corners': False,
'coordinate_mapping': 'identity',
'interpolation': 'nearest_neighbor',
'normalize': self.normalize,
}
out_features = ops.continuous_conv(**self._conv_values)
self._conv_output = out_features
if self.use_bias:
out_features += self.bias
out_features = self.activation(out_features)
if out_positions_split is not None:
out_features = tf.RaggedTensor.from_row_splits(
values=out_features, row_splits=out_positions_split)
return out_features
def compute_output_shape(self, inp_features_shape):
return tf.TensorShape((None, self.filters))
统计和调试。
class SparseConvTranspose(tf.keras.layers.Layer):
稀疏转置卷积。该层计算转置卷积,仅在指定的输出位置进行计算。