새소식

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의 길이로 바꿔주고 있습니다. 

Filetree

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      # 데이터 전처리 유틸리티
    └── [기타 유틸리티 파일들]

 

T-Net

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하도록 전처리를 하게 됩니다. 

F-Net

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

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

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