Exemplo n.º 1
0
def sample_and_group(npoint, radius, nsample, xyz, points, knn=False, use_xyz=True):
    '''
    Input:
        npoint: int32
        radius: float32
        nsample: int32
        xyz: (batch_size, ndataset, 3) TF tensor
        points: (batch_size, ndataset, channel) TF tensor, if None will just use xyz as points
        knn: bool, if True use kNN instead of radius search
        use_xyz: bool, if True concat XYZ with local point features, otherwise just use point features
    Output:
        new_xyz: (batch_size, npoint, 3) TF tensor
        new_points: (batch_size, npoint, nsample, 3+channel) TF tensor
        idx: (batch_size, npoint, nsample) TF tensor, indices of local points as in ndataset points
        grouped_xyz: (batch_size, npoint, nsample, 3) TF tensor, normalized point XYZs
            (subtracted by seed point XYZ) in local regions
    '''

    new_xyz = gather_point(xyz, farthest_point_sample(npoint, xyz))  # (batch_size, npoint, 3)
    if knn:
        _, idx = knn_point(nsample, xyz, new_xyz)
    else:
        idx, pts_cnt = query_ball_point(radius, nsample, xyz, new_xyz)
    grouped_xyz = group_point(xyz, idx)  # (batch_size, npoint, nsample, 3)
    grouped_xyz -= tf.tile(tf.expand_dims(new_xyz, 2), [1, 1, nsample, 1])  # translation normalization
    if points is not None:
        grouped_points = group_point(points, idx)  # (batch_size, npoint, nsample, channel)
        if use_xyz:
            new_points = tf.concat([grouped_xyz, grouped_points], axis=-1)  # (batch_size, npoint, nample, 3+channel)
        else:
            new_points = grouped_points
    else:
        new_points = grouped_xyz

    return new_xyz, new_points, idx, grouped_xyz
    def __init__(self, points, features, num_class, is_training, setting,
                 task):
        xconv_params = setting.xconv_params
        fc_params = setting.fc_params
        with_X_transformation = setting.with_X_transformation
        sorting_method = setting.sorting_method
        N = tf.shape(points)[0]

        if setting.with_fps:
            from sampling import tf_sampling

        self.layer_pts = [points]
        if features is None:
            self.layer_fts = [features]
        else:
            C_fts = xconv_params[0][-1] // 2
            features_hd = pf.dense(features, C_fts, 'features_hd', is_training)
            self.layer_fts = [features_hd]

        for layer_idx, layer_param in enumerate(xconv_params):
            tag = 'xconv_' + str(layer_idx + 1) + '_'
            K, D, P, C = layer_param

            # get k-nearest points
            pts = self.layer_pts[-1]
            fts = self.layer_fts[-1]
            if P == -1:
                qrs = points
            else:
                if setting.with_fps:
                    qrs = tf_sampling.gather_point(
                        pts, tf_sampling.farthest_point_sample(P,
                                                               pts))  # (N,P,3)
                else:
                    qrs = tf.slice(pts, (0, 0, 0), (-1, P, -1),
                                   name=tag + 'qrs')  # (N, P, 3)
            self.layer_pts.append(qrs)

            if layer_idx == 0:
                C_pts_fts = C // 2 if fts is None else C // 4
                depth_multiplier = 4
            else:
                C_prev = xconv_params[layer_idx - 1][-1]
                C_pts_fts = C_prev // 4
                depth_multiplier = math.ceil(C / C_prev)
            fts_xconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts,
                              is_training, with_X_transformation,
                              depth_multiplier, sorting_method)
            self.layer_fts.append(fts_xconv)

        if task == 'segmentation':
            for layer_idx, layer_param in enumerate(setting.xdconv_params):
                tag = 'xdconv_' + str(layer_idx + 1) + '_'
                K, D, pts_layer_idx, qrs_layer_idx = layer_param

                pts = self.layer_pts[pts_layer_idx + 1]
                fts = self.layer_fts[
                    pts_layer_idx +
                    1] if layer_idx == 0 else self.layer_fts[-1]
                qrs = self.layer_pts[qrs_layer_idx + 1]
                fts_qrs = self.layer_fts[qrs_layer_idx + 1]
                _, _, P, C = xconv_params[qrs_layer_idx]
                _, _, _, C_prev = xconv_params[pts_layer_idx]
                C_pts_fts = C_prev // 4
                depth_multiplier = 1
                fts_xdconv = xconv(pts, fts, qrs, tag, N, K, D, P, C,
                                   C_pts_fts, is_training,
                                   with_X_transformation, depth_multiplier,
                                   sorting_method)
                fts_concat = tf.concat([fts_xdconv, fts_qrs],
                                       axis=-1,
                                       name=tag + 'fts_concat')
                fts_fuse = pf.dense(fts_concat, C, tag + 'fts_fuse',
                                    is_training)
                self.layer_pts.append(qrs)
                self.layer_fts.append(fts_fuse)

        self.fc_layers = [self.layer_fts[-1]]
        for layer_idx, layer_param in enumerate(fc_params):
            channel_num, drop_rate = layer_param
            fc = pf.dense(self.fc_layers[-1], channel_num,
                          'fc{:d}'.format(layer_idx), is_training)
            fc_drop = tf.layers.dropout(fc,
                                        drop_rate,
                                        training=is_training,
                                        name='fc{:d}_drop'.format(layer_idx))
            self.fc_layers.append(fc_drop)

        logits = pf.dense(self.fc_layers[-1],
                          num_class,
                          'logits',
                          is_training,
                          with_bn=False,
                          activation=None)
        if task == 'classification':
            logits_mean = tf.reduce_mean(logits,
                                         axis=1,
                                         keep_dims=True,
                                         name='logits_mean')
            self.logits = tf.cond(is_training, lambda: logits,
                                  lambda: logits_mean)
        elif task == 'segmentation':
            self.logits = logits
        else:
            print('Unknown task!')
            exit()
        self.probs = tf.nn.softmax(self.logits, name='probs')
Exemplo n.º 3
0
    def __init__(self, points, features, num_class, is_training, setting, task):
        xconv_params = setting.xconv_params
        fc_params = setting.fc_params
        with_X_transformation = setting.with_X_transformation
        sorting_method = setting.sorting_method
        N = tf.shape(points)[0]

        if setting.sampling == 'fps':
            from sampling import tf_sampling

        self.layer_pts = [points]
        if features is None:
            self.layer_fts = [features]
        else:
            C_fts = xconv_params[0]['C'] // 2
            features_hd = pf.dense(features, C_fts, 'features_hd', is_training)
            self.layer_fts = [features_hd]

        for layer_idx, layer_param in enumerate(xconv_params):
            tag = 'xconv_' + str(layer_idx + 1) + '_'
            K = layer_param['K']
            D = layer_param['D']
            P = layer_param['P']
            C = layer_param['C']
            links = layer_param['links']
            if setting.sampling != 'random' and links:
                print('Error: flexible links are supported only when random sampling is used!')
                exit()

            # get k-nearest points
            pts = self.layer_pts[-1]
            fts = self.layer_fts[-1]
            if P == -1 or (layer_idx > 0 and P == xconv_params[layer_idx - 1]['P']):
                qrs = self.layer_pts[-1]
            else:
                if setting.sampling == 'fps':
                    indices = tf_sampling.farthest_point_sample(P, pts)
                    qrs = tf_sampling.gather_point(pts, indices)  # (N,P,3)
                elif setting.sampling == 'ids':
                    indices = pf.inverse_density_sampling(pts, K, P)
                    qrs = tf.gather_nd(pts, indices)
                elif setting.sampling == 'random':
                    qrs = tf.slice(pts, (0, 0, 0), (-1, P, -1), name=tag + 'qrs')  # (N, P, 3)
                else:
                    print('Unknown sampling method!')
                    exit()
            self.layer_pts.append(qrs)

            if layer_idx == 0:
                C_pts_fts = C // 2 if fts is None else C // 4
                depth_multiplier = 4
            else:
                C_prev = xconv_params[layer_idx - 1]['C']
                C_pts_fts = C_prev // 4
                depth_multiplier = math.ceil(C / C_prev)
            fts_xconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts, is_training, with_X_transformation,
                              depth_multiplier, sorting_method, layer_idx != len(xconv_params) - 1)
            fts_list = []
            for link in links:
                fts_from_link = self.layer_fts[link]
                if fts_from_link is not None:
                    fts_slice = tf.slice(fts_from_link, (0, 0, 0), (-1, P, -1),
                                         name=tag + 'fts_slice_' + str(-link))
                    C_forward = math.ceil(fts_slice.get_shape().as_list()[-1] / (-link))
                    fts_forward = pf.dense(fts_slice, C_forward, tag + 'fts_forward_' + str(-link), is_training)
                    fts_list.append(fts_forward)
            if fts_list:
                fts_list.append(fts_xconv)
                self.layer_fts.append(tf.concat(fts_list, axis=-1, name=tag + 'fts_list_concat'))
            else:
                self.layer_fts.append(fts_xconv)

        if task == 'segmentation':
            for layer_idx, layer_param in enumerate(setting.xdconv_params):
                tag = 'xdconv_' + str(layer_idx + 1) + '_'
                K = layer_param['K']
                D = layer_param['D']
                pts_layer_idx = layer_param['pts_layer_idx']
                qrs_layer_idx = layer_param['qrs_layer_idx']

                pts = self.layer_pts[pts_layer_idx + 1]
                fts = self.layer_fts[pts_layer_idx + 1] if layer_idx == 0 else self.layer_fts[-1]
                qrs = self.layer_pts[qrs_layer_idx + 1]
                fts_qrs = self.layer_fts[qrs_layer_idx + 1]
                P = xconv_params[qrs_layer_idx]['P']
                C = xconv_params[qrs_layer_idx]['C']
                C_prev = xconv_params[pts_layer_idx]['C']
                C_pts_fts = C_prev // 4
                depth_multiplier = 1
                fts_xdconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts, is_training, with_X_transformation,
                                   depth_multiplier, sorting_method)
                fts_concat = tf.concat([fts_xdconv, fts_qrs], axis=-1, name=tag + 'fts_concat')
                fts_fuse = pf.dense(fts_concat, C, tag + 'fts_fuse', is_training)
                self.layer_pts.append(qrs)
                self.layer_fts.append(fts_fuse)

        self.fc_layers = [self.layer_fts[-1]]
        for layer_idx, layer_param in enumerate(fc_params):
            C = layer_param['C']
            dropout_rate = layer_param['dropout_rate']
            fc = pf.dense(self.fc_layers[-1], C, 'fc{:d}'.format(layer_idx), is_training)
            fc_drop = tf.layers.dropout(fc, dropout_rate, training=is_training, name='fc{:d}_drop'.format(layer_idx))
            self.fc_layers.append(fc_drop)

        if task == 'classification':
            fc_mean = tf.reduce_mean(self.fc_layers[-1], axis=1, keep_dims=True, name='fc_mean')
            self.fc_layers[-1] = tf.cond(is_training, lambda: self.fc_layers[-1], lambda: fc_mean)

        self.logits = pf.dense(self.fc_layers[-1], num_class, 'logits', is_training, with_bn=False, activation=None)
        self.probs = tf.nn.softmax(self.logits, name='probs')
Exemplo n.º 4
0
ops.NoGradient('AuctionMatch')

# TF1.0 API requires set shape in C++
# @tf.RegisterShape('AuctionMatch')
# def _auction_match_shape(op):
# 	shape1=op.inputs[0].get_shape().with_rank(3)
# 	shape2=op.inputs[1].get_shape().with_rank(3)
# 	return [
# 		tf.TensorShape([shape1.dims[0],shape1.dims[1]]),
# 		tf.TensorShape([shape2.dims[0],shape2.dims[1]])
# 	]

if __name__=='__main__':
    from grouping import tf_grouping
    from sampling import tf_sampling

    npoint=4096
    xyz1_in=tf.placeholder(tf.float32,shape=(32,npoint,3))
    xyz2_in=tf.placeholder(tf.float32,shape=(32,npoint,3))
    matchl_out,matchr_out=auction_match(xyz1_in,xyz2_in)
    matched_out=tf_sampling.gather_point(xyz2_in,matchl_out)
    import numpy as np
    np.random.seed(100)
    xyz1=np.random.randn(32,npoint,3).astype('float32')
    xyz2=xyz1.copy()+np.random.randn(32,npoint,3)*0.01
    for i in range(len(xyz2)):
        xyz2[i]=np.roll(xyz2[i],i,axis=0)
    with tf.Session('') as sess:
        ret=sess.run(matched_out,feed_dict={xyz1_in:xyz1,xyz2_in:xyz2})
    print(((xyz1-ret)**2).mean())
Exemplo n.º 5
0
    def __init__(self, points, features, images, image_xy, num_class,
                 is_training, setting, task):

        print("points:", points)
        print("features:", features)

        xconv_params = setting.xconv_params
        print("xconv_params:", xconv_params)

        fc_params = setting.fc_params
        print("fc_params:", fc_params)

        # 从配置文件中获取后续分支的参数
        extra_branch_xconv_params = setting.extra_branch_xconv_params
        extra_branch_fc_params = setting.extra_branch_fc_params
        mask_sample_num = setting.mask_sample_num

        with_X_transformation = setting.with_X_transformation
        sorting_method = setting.sorting_method

        N = tf.shape(points)[0]
        point_num = tf.shape(points)[1]

        if setting.with_fps:
            from sampling import tf_sampling

        self.layer_pts = [points]

        if features is None:
            self.layer_fts = [features]
        else:
            C_fts = xconv_params[0][-1] // 2
            features_hd = pf.dense(features, C_fts, 'features_hd', is_training)
            self.layer_fts = [features_hd]

        for layer_idx, layer_param in enumerate(xconv_params):

            tag = 'xconv_' + str(layer_idx + 1) + '_'
            K, D, P, C = layer_param

            fts = self.layer_fts[-1]

            # get k centroid points
            pts = self.layer_pts[-1]

            if P == -1:
                qrs = self.layer_pts[-1]
            else:
                if setting.with_fps:
                    fps_indices = tf_sampling.farthest_point_sample(P, pts)
                    batch_indices = tf.tile(
                        tf.reshape(tf.range(N), (-1, 1, 1)), (1, P, 1))
                    fps_indices_g = tf.concat(
                        [batch_indices,
                         tf.expand_dims(fps_indices, -1)],
                        axis=-1)
                    qrs = tf.gather_nd(pts, fps_indices_g,
                                       name=tag + 'qrs')  # (N, P, 3)
                else:
                    qrs = tf.slice(pts, (0, 0, 0), (-1, P, -1),
                                   name=tag + 'qrs')  # (N, P, 3)

            self.layer_pts.append(qrs)

            if layer_idx == 0:
                C_pts_fts = C // 2 if fts is None else C // 4
                depth_multiplier = 4
            else:
                C_prev = xconv_params[layer_idx - 1][-1]
                C_pts_fts = C_prev // 4
                depth_multiplier = math.ceil(C / C_prev)

            fts_xconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts,
                              is_training, with_X_transformation,
                              depth_multiplier, sorting_method, False)
            self.layer_fts.append(fts_xconv)

        if task == 'segmentation':
            for layer_idx, layer_param in enumerate(setting.xdconv_params):
                tag = 'xdconv_' + str(layer_idx + 1) + '_'
                K, D, pts_layer_idx, qrs_layer_idx = layer_param

                pts = self.layer_pts[pts_layer_idx + 1]
                fts = self.layer_fts[
                    pts_layer_idx +
                    1] if layer_idx == 0 else self.layer_fts[-1]
                qrs = self.layer_pts[qrs_layer_idx + 1]
                fts_qrs = self.layer_fts[qrs_layer_idx + 1]
                _, _, P, C = xconv_params[qrs_layer_idx]

                C_pts_fts = C_prev // 4
                depth_multiplier = 1
                fts_xdconv = xconv(pts, fts, qrs, tag, N, K, D, P, C,
                                   C_pts_fts, is_training,
                                   with_X_transformation, depth_multiplier,
                                   sorting_method)
                fts_concat = tf.concat([fts_xdconv, fts_qrs],
                                       axis=-1,
                                       name=tag + 'fts_concat')
                fts_fuse = pf.dense(fts_concat, C, tag + 'fts_fuse',
                                    is_training)
                self.layer_pts.append(qrs)
                self.layer_fts.append(fts_fuse)

        self.fc_layers = [self.layer_fts[-1]]
        for layer_idx, layer_param in enumerate(fc_params):
            channel_num, drop_rate = layer_param
            fc = pf.dense(self.fc_layers[-1], channel_num,
                          'fc{:d}'.format(layer_idx), is_training)
            fc_drop = tf.layers.dropout(fc,
                                        drop_rate,
                                        training=is_training,
                                        name='fc{:d}_drop'.format(layer_idx))
            self.fc_layers.append(fc_drop)

        if task == 'classification':
            fc_mean = tf.reduce_mean(self.fc_layers[-1],
                                     axis=1,
                                     keep_dims=True,
                                     name='fc_mean')
            self.fc_layers[-1] = tf.cond(is_training,
                                         lambda: self.fc_layers[-1],
                                         lambda: fc_mean)

        self.logits = pf.dense(self.fc_layers[-1],
                               num_class,
                               'logits',
                               is_training,
                               with_bn=False,
                               activation=None)
        self.probs = tf.nn.softmax(self.logits, name='probs')

        # 从分割结果获取Mask点云(车辆点云)
        probs_others = tf.slice(self.probs, [0, 0, 0], [N, point_num, 1])
        probs_instance = tf.slice(self.probs, [0, 0, 1], [N, point_num, 1])
        hold_sub_mask = tf.subtract(probs_instance,
                                    probs_others,
                                    name="hold_sub_mask")
        indices_mask = tf.py_func(pf.instance_choice,
                                  [hold_sub_mask, mask_sample_num], tf.int32)
        indices_mask.set_shape(
            [hold_sub_mask.get_shape()[0], mask_sample_num, 2])
        points_mask = tf.gather_nd(points, indices_mask, name='points_mask')

        # 计算mask点云重心
        if setting.with_xyz_res:
            points_mask_mean = tf.reduce_mean(points_mask,
                                              axis=-2,
                                              keep_dims=True,
                                              name='points_mask_mean')
            points_mask_mean_sq = tf.squeeze(points_mask_mean,
                                             name='points_mask_mean_sq')
            points_mask_centroid = tf.subtract(points_mask,
                                               points_mask_mean,
                                               name='points_mask_centroid')
            eb_pts = points_mask_centroid
        else:
            eb_pts = points_mask
        # 获取mask点云特征
        if features is None:
            features_mask_hd = None
        else:
            C_fts = extra_branch_xconv_params[0][-1] // 2
            features_mask = tf.gather_nd(features,
                                         indices_mask,
                                         name='features_mask')
            mask_features_hd = pf.dense(features_mask, C_fts,
                                        'mask_features_hd', is_training)
        eb_fts = mask_features_hd

        # Bbox分支(尺寸与位置分支)
        self.bbox_layer_fts = [eb_fts]
        self.bbox_layer_pts = [eb_pts]
        for layer_idx, layer_param in enumerate(extra_branch_xconv_params):
            tag = 'bbox_branch_xconv_' + str(layer_idx + 1) + '_'
            K, D, P, C = layer_param
            pts = self.bbox_layer_pts[-1]
            fts = self.bbox_layer_fts[-1]
            # get centroid points
            if P == -1:
                qrs = eb_pts
            else:
                if setting.eb_with_fps:
                    fps_indices = tf_sampling.farthest_point_sample(P, pts)
                    batch_indices = tf.tile(
                        tf.reshape(tf.range(N), (-1, 1, 1)), (1, P, 1))
                    fps_indices_g = tf.concat(
                        [batch_indices,
                         tf.expand_dims(fps_indices, -1)],
                        axis=-1)
                    qrs = tf.gather_nd(pts, fps_indices_g,
                                       name=tag + 'qrs')  # (N, P, 3)
                else:
                    qrs = tf.slice(pts, (0, 0, 0), (-1, P, -1),
                                   name=tag + 'qrs')  # (N, P, 3)
            self.bbox_layer_pts.append(qrs)
            if layer_idx == 0:
                C_pts_fts = C // 2 if fts is None else C // 4
                depth_multiplier = 4
            else:
                C_prev = xconv_params[layer_idx - 1][-1]
                C_pts_fts = C_prev // 4
                depth_multiplier = math.ceil(C / C_prev)
            fts_xconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts,
                              is_training, with_X_transformation,
                              depth_multiplier, sorting_method, False)
            self.bbox_layer_fts.append(fts_xconv)

        # HWL 预测分支 以用maxpooling特征进行预测为例
        self.hwl_fc_layers = [
            tf.reduce_max(self.bbox_layer_fts[-1], axis=1, name='hwl_fts_max')
        ]
        for layer_idx, layer_param in enumerate(extra_branch_fc_params):
            channel_num, drop_rate = layer_param
            fc = pf.dense(self.hwl_fc_layers[-1],
                          channel_num,
                          'hwl_fc{:d}'.format(layer_idx),
                          is_training,
                          with_bn=setting.hwl_branch_setting["with_bn"])
            fc_drop = tf.layers.dropout(
                fc,
                drop_rate,
                training=is_training,
                name='hwl_fc{:d}_drop'.format(layer_idx))
            self.hwl_fc_layers.append(fc_drop)
        self.logits_hwl = pf.dense(self.hwl_fc_layers[-1],
                                   3,
                                   'logits_hwl',
                                   is_training,
                                   with_bn=False,
                                   activation=None)

        # XYZ 预测分支 以用maxpooling特征进行预测为例
        self.xyz_fc_layers = [
            tf.reduce_max(self.bbox_layer_fts[-1], axis=1, name='xyz_fts_max')
        ]
        for layer_idx, layer_param in enumerate(extra_branch_fc_params):
            channel_num, drop_rate = layer_param
            fc = pf.dense(self.xyz_fc_layers[-1],
                          channel_num,
                          'xyz_fc{:d}'.format(layer_idx),
                          is_training,
                          with_bn=setting.xyz_branch_setting["with_bn"])
            fc_drop = tf.layers.dropout(
                fc,
                drop_rate,
                training=is_training,
                name='xyz_fc{:d}_drop'.format(layer_idx))
            self.xyz_fc_layers.append(fc_drop)
        if setting.with_xyz_res:
            logits_xyz_res = pf.dense(self.xyz_fc_layers[-1],
                                      3,
                                      'logits_xyz_res',
                                      is_training,
                                      with_bn=False,
                                      activation=None)
            self.logits_xyz = tf.add(points_mask_mean_sq,
                                     logits_xyz_res,
                                     name='logits_xyz')
        else:
            self.logits_xyz = pf.dense(self.xyz_fc_layers[-1],
                                       3,
                                       'logits_xyz_res',
                                       is_training,
                                       with_bn=False,
                                       activation=None)

        # Ry分支(旋转角分支)
        self.ry_layer_fts = [eb_fts]
        self.ry_layer_pts = [eb_pts]
        for layer_idx, layer_param in enumerate(extra_branch_xconv_params):
            tag = 'ry_branch_xconv_' + str(layer_idx + 1) + '_'
            K, D, P, C = layer_param
            fts = self.ry_layer_fts[-1]
            # get centroid points
            pts = self.ry_layer_pts[-1]
            if P == -1:
                qrs = eb_pts
            else:
                if setting.eb_with_fps:
                    fps_indices = tf_sampling.farthest_point_sample(P, pts)
                    qrs = tf_sampling.gather_point(pts, fps_indices)  # (N,P,3)
                else:
                    qrs = tf.slice(pts, (0, 0, 0), (-1, P, -1),
                                   name=tag + 'qrs')  # (N, P, 3)
            self.ry_layer_pts.append(qrs)
            if layer_idx == 0:
                C_pts_fts = C // 2 if fts is None else C // 4
                depth_multiplier = 4
            else:
                C_prev = xconv_params[layer_idx - 1][-1]
                C_pts_fts = C_prev // 4
                depth_multiplier = math.ceil(C / C_prev)
            fts_xconv = xconv(pts, fts, qrs, tag, N, K, D, P, C, C_pts_fts,
                              is_training, with_X_transformation,
                              depth_multiplier, sorting_method, False)
            self.ry_layer_fts.append(fts_xconv)

        # Ry 分类预测分支 以用maxpooling特征进行预测为例
        self.ry_fc_layers = [
            tf.reduce_max(self.ry_layer_fts[-1], axis=1, name='ry_fts_max')
        ]
        for layer_idx, layer_param in enumerate(extra_branch_fc_params):
            channel_num, drop_rate = layer_param
            fc = pf.dense(self.ry_fc_layers[-1],
                          channel_num,
                          'ry_fc{:d}'.format(layer_idx),
                          is_training,
                          with_bn=setting.ry_branch_setting["with_bn"])
            fc_drop = tf.layers.dropout(
                fc,
                drop_rate,
                training=is_training,
                name='ry_fc{:d}_drop'.format(layer_idx))
            self.ry_fc_layers.append(fc_drop)
        self.logits_ry = pf.dense(self.ry_fc_layers[-1],
                                  24,
                                  'logits_ry',
                                  is_training,
                                  with_bn=False,
                                  activation=None)
        self.probs_ry = tf.nn.softmax(self.logits_ry, name='probs_ry')