새소식

Point Cloud

PointNet의 input point cloud processing에 대해서

  • -

https://github.com/charlesq34/pointnet.git

 

GitHub - charlesq34/pointnet: PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation - charlesq34/pointnet

github.com

Point cloud를 input으로 받는 딥러닝 모델을 설계할 때는 항상 고민에 빠지게 되는 지점은 '길이가 모두 다른 point cloud를 어떻게 정규화를 해 줄 것인가?'인 것 같습니다. 길이를 고정해놓고 패딩을 줄 수도 있고, 정규화 네트워크를 하나 더 붙여 줄 수도 있는데, pointnet에서는 input transform net을 통해서 가변 길이의 point cloud를 모델 input tensor의 길이로 바꿔주고 있습니다. 

pointnet/ ├── LICENSE ├── README.md ├── doc/ ├── evaluate.py # 모델 평가 스크립트 ├── models/ # 핵심 모델 구현 │ ├── pointnet_cls.py # 분류 모델 │ ├── pointnet_seg.py # 세그멘테이션 모델 │ ├── transform_nets.py # 특징 변환 네트워크 │ └── pointnet_cls_basic.py # 기본 분류 모델 ├── part_seg/ # 파트 세그멘테이션 │ ├── train.py │ └── [기타 파트 세그멘테이션 관련 파일들] ├── provider.py # 데이터 로딩/전처리 유틸리티 ├── sem_seg/ # 시맨틱 세그멘테이션 │ ├── batch_inference.py │ ├── model.py │ ├── train.py │ └── [기타 시맨틱 세그멘테이션 관련 파일들] ├── train.py # 메인 학습 스크립트 └── utils/ # 유틸리티 함수들 ├── tf_util.py # TensorFlow 유틸리티 ├── data_prep_util.py # 데이터 전처리 유틸리티 └── [기타 유틸리티 파일들]

 

Input Transform Network

# models/pointnet_cls.py의 get_model 함수 with tf.variable_scope('transform_net1') as sc: transform = input_transform_net(point_cloud, is_training, bn_decay, K=3) point_cloud_transformed = tf.matmul(point_cloud, transform)

input_transform_net은 포인트 클라우드의 공간적 변환을 학습하는 네트워크입니다. 이를 통해서 입력에 대해 3x3 transformation matrix를 학습하도록 합니다. 

  • 입력 : point cloud (BxNx3, B: 배치 크기, N: 점 개수, 3: XYZ 좌표)
  • 출력 : 3xK 크기의 transformation matrix (여기서 K=3)
def input_transform_net(point_cloud, is_training, bn_decay=None, K=3): """ Input (XYZ) Transform Net, input is BxNx3 gray image Return: Transformation matrix of size 3xK """ batch_size = point_cloud.get_shape()[0].value num_point = point_cloud.get_shape()[1].value input_image = tf.expand_dims(point_cloud, -1) net = tf_util.conv2d(input_image, 64, [1,3], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv1', bn_decay=bn_decay) net = tf_util.conv2d(net, 128, [1,1], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv2', bn_decay=bn_decay) net = tf_util.conv2d(net, 1024, [1,1], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv3', bn_decay=bn_decay) net = tf_util.max_pool2d(net, [num_point,1], padding='VALID', scope='tmaxpool') net = tf.reshape(net, [batch_size, -1]) net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='tfc1', bn_decay=bn_decay) net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='tfc2', bn_decay=bn_decay) with tf.variable_scope('transform_XYZ') as sc: assert(K==3) weights = tf.get_variable('weights', [256, 3*K], initializer=tf.constant_initializer(0.0), dtype=tf.float32) biases = tf.get_variable('biases', [3*K], initializer=tf.constant_initializer(0.0), dtype=tf.float32) biases += tf.constant([1,0,0,0,1,0,0,0,1], dtype=tf.float32) transform = tf.matmul(net, weights) transform = tf.nn.bias_add(transform, biases) transform = tf.reshape(transform, [batch_size, 3, K]) return transform

이 네트워크를 통해서 입력 포인트 클라우드의 방향과 위치를 정규화하고 회전, 이동 등의 기하학적 변환에 대해 invariant하도록 전처리를 하게 됩니다. 

Feature Transform Network

Feature transform network는 input transform network와 유사한 구조를 가지지만, 특징 공간에서의 변환을 학습하는 네트워크입니다. 

  • 입력 : 특징 맵 (BxNx1xK, B: 배치 크기, N: 점 개수, K: 특징 차원, 기본값은 64)
  • 출력 : KxK 크기의 transformation matrix
def feature_transform_net(inputs, is_training, bn_decay=None, K=64): """ Feature Transform Net, input is BxNx1xK Return: Transformation matrix of size KxK """ batch_size = inputs.get_shape()[0].value num_point = inputs.get_shape()[1].value net = tf_util.conv2d(inputs, 64, [1,1], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv1', bn_decay=bn_decay) net = tf_util.conv2d(net, 128, [1,1], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv2', bn_decay=bn_decay) net = tf_util.conv2d(net, 1024, [1,1], padding='VALID', stride=[1,1], bn=True, is_training=is_training, scope='tconv3', bn_decay=bn_decay) net = tf_util.max_pool2d(net, [num_point,1], padding='VALID', scope='tmaxpool') net = tf.reshape(net, [batch_size, -1]) net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='tfc1', bn_decay=bn_decay) net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='tfc2', bn_decay=bn_decay) with tf.variable_scope('transform_feat') as sc: weights = tf.get_variable('weights', [256, K*K], initializer=tf.constant_initializer(0.0), dtype=tf.float32) biases = tf.get_variable('biases', [K*K], initializer=tf.constant_initializer(0.0), dtype=tf.float32) biases += tf.constant(np.eye(K).flatten(), dtype=tf.float32) transform = tf.matmul(net, weights) transform = tf.nn.bias_add(transform, biases) transform = tf.reshape(transform, [batch_size, K, K]) return transform

이 네트워크는 특징 공간에서 정규화를 수행해 특징의 alignment를 개선하고 더 discriminative한 특징 추출을 할 수 있게 합니다. 따라서 예를 들어 T-Net이 의자가 어느 방향을 향하고 있든 같은 방향으로 정규화시킨다면, F-Net은 의자의 다리, 등받이 등의 부분적인 특징들을 일관되게 정규화하는 네트워크입니다. 

그래서 T-Net을 거치고 F-Net을 거치면, T-Net에서는 원본 데이터의 기하학적 변환을 처리하고 F-Net에서 추출된 특징들의 고차원 변환을 처리하는 계층적인 구조를 가집니다. 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.