RandLA-Net 训练自定义数据集

在这里插入图片描述
在这里插入图片描述

https://arxiv.org/abs/1911.11236


搭建训练环境

  1. git clone https://github.com/QingyongHu/RandLA-Net.git
  2. 搭建 python 环境 , 这里我用的 3.9
    conda create -n randlanet python=3.9
    source activate randlanet
    pip install tensorflow==2.15.0 -i https://pypi.tuna.tsinghua.edu.cn/simple  --timeout=120
    pip install -r helper_requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
    pip install Cython -i https://pypi.tuna.tsinghua.edu.cn/simple
    conda install -c conda-forge scikit-learn
    
  3. cd utils/cpp_wrappers/cpp_subsampling/ , 执行 python setup.py build_ext --inplace , 输出 grid_subsampling.cpython-39-x86_64-linux-gnu.so
  4. cd nearest_neighbors , 执行 python setup.py build_ext --inplace, 输出 nearest_neighbors.cpython-39-x86_64-linux-gnu.so

制作数据集

  1. 这里我用 CloudCompare 标注的数据集 , 具体标注方法,上网找找.
  2. 创建 make_train_dataset.py, 开始生成训练数据集
    # 写这段代码的时候,只有上帝和我知道它是干嘛的
    # 现在,只有上帝知道
    # @File : make_cloud_train_datasets.py
    # @Author : J.
    # @desc : 生成 RandLanet 训练数据集
    
    from sklearn.neighbors import KDTree
    from os.path import join, exists, dirname, abspath
    import numpy as np
    import os, glob, pickle
    import sys
    
    BASE_DIR = dirname(abspath(__file__))
    ROOT_DIR = dirname(BASE_DIR)
    sys.path.append(BASE_DIR)
    sys.path.append(ROOT_DIR)
    from helper_ply import write_ply
    from helper_tool import DataProcessing as DP
    
    grid_size = 0.01
    dataset_path = './data/sample/original_data'
    original_pc_folder = join(dirname(dataset_path), 'original_ply')
    sub_pc_folder = join(dirname(dataset_path), 'input_{:.3f}'.format(grid_size))
    os.mkdir(original_pc_folder) if not exists(original_pc_folder) else None
    os.mkdir(sub_pc_folder) if not exists(sub_pc_folder) else None
    
    railway_cnt = 0
    backgroud_cnt = 0
    for pc_path in glob.glob(join(dataset_path, '*.txt')):
        file_name = os.path.basename(pc_path)[:-4]
        if exists(join(sub_pc_folder, file_name + '_KDTree.pkl')):
            continue
        pc = np.loadtxt(pc_path)
        labels = pc[:, -1].astype(np.uint8)
        values , counts =  np.unique(labels,return_counts = True)
        for i in range(len(values)):
        	# 我标注2个类别(包含背景类别)
        	# 统计每个类别点的数量
            if values[i] == 0:
                backgroud_cnt = backgroud_cnt + counts[i]
            elif values[i] == 1:
                 railway_cnt = railway_cnt + counts[i]
    
     
        full_ply_path = join(original_pc_folder, file_name + '.ply')
        #  Subsample to save space
        sub_points, sub_colors, sub_labels = DP.grid_sub_sampling(pc[:, :3].astype(np.float32),
                                                                  pc[:, 3:6].astype(np.uint8), labels, 0.01)
        
        sub_labels = np.squeeze(sub_labels)
        write_ply(full_ply_path, (sub_points, sub_colors, sub_labels), ['x', 'y', 'z', 'red', 'green', 'blue', 'class'])
        # save sub_cloud and KDTree file
        sub_xyz, sub_colors, sub_labels = DP.grid_sub_sampling(sub_points, sub_colors, sub_labels, grid_size)
        sub_colors = sub_colors / 255.0
        sub_labels = np.squeeze(sub_labels)
        sub_ply_file = join(sub_pc_folder, file_name + '.ply')
        write_ply(sub_ply_file, [sub_xyz, sub_colors, sub_labels], ['x', 'y', 'z', 'red', 'green', 'blue', 'class'])
    
        search_tree = KDTree(sub_xyz, leaf_size=50)
        kd_tree_file = join(sub_pc_folder, file_name + '_KDTree.pkl')
        with open(kd_tree_file, 'wb') as f:
            pickle.dump(search_tree, f)
        proj_idx = np.squeeze(search_tree.query(sub_points, return_distance=False))
        proj_idx = proj_idx.astype(np.int32)
        proj_save = join(sub_pc_folder, file_name + '_proj.pkl')
        with open(proj_save, 'wb') as f:
            pickle.dump([proj_idx, labels], f)
    # 统计每个类别个数
    print("----> backgroud_cnt: " + str(backgroud_cnt))
    print("----> railway_cnt: " + str(railway_cnt))
    
  3. 修改 helper_tools.py
     #import cpp_wrappers.cpp_subsampling.grid_subsampling as cpp_subsampling
     #import nearest_neighbors.lib.python.nearest_neighbors as nearest_neighbors
     # 修改成
     import utils.cpp_wrappers.cpp_subsampling.grid_subsampling as cpp_subsampling
     import utils.nearest_neighbors.nearest_neighbors as nearest_neighbors
    
    ...
    # 复制一个 起个自己名字 
    class ConfigSample:
        k_n = 16  # KNN
        num_layers = 5  # Number of layers
        num_points = 16000  # Number of input points
        # 包含背景类别,如果想排除背景类别, 修改 ignored_labels
        num_classes = 2  # Number of valid classes  
        sub_grid_size = 0.01  # preprocess_parameter # Todo
        batch_size = 4  # batch_size during training
        val_batch_size = 2  # batch_size during validation and test
        train_steps = 500  # Number of steps per epochs
        val_steps = 3  # Number of validation steps per epoch
        sub_sampling_ratio = [4, 4, 4, 4, 2]  # sampling ratio of random sampling at each layer
        d_out = [16, 64, 128, 256, 512]  # feature dimension
        noise_init = 3.5  # noise initial parameter
        max_epoch = 100  # maximum epoch during training
        learning_rate = 1e-2  # initial learning rate
        lr_decays = {i: 0.95 for i in range(0, 500)}  # decay rate of learning rate
        train_sum_dir = 'train_log'
        saving = True
        saving_path = None
      
        augment_scale_anisotropic = True
        augment_symmetries = [True, False, False]
        augment_rotation = 'vertical'
        augment_scale_min = 0.8
        augment_scale_max = 1.2
        augment_noise = 0.001
        augment_occlusion = 'none'
        augment_color = 0.8
    
    @staticmethod
        def get_class_weights(dataset_name):
            # pre-calculate the number of points in each category
            num_per_class = []
            if dataset_name is 'S3DIS':
                num_per_class = np.array([3370714, 2856755, 4919229, 318158, 375640, 478001, 974733,
                                          650464, 791496, 88727, 1284130, 229758, 2272837], dtype=np.int32)
            elif dataset_name is 'Semantic3D':
                num_per_class = np.array([5181602, 5012952, 6830086, 1311528, 10476365, 946982, 334860, 269353],
                                         dtype=np.int32)
            elif dataset_name is 'SemanticKITTI':
                num_per_class = np.array([55437630, 320797, 541736, 2578735, 3274484, 552662, 184064, 78858,
                                          240942562, 17294618, 170599734, 6369672, 230413074, 101130274, 476491114,
                                          9833174, 129609852, 4506626, 1168181])
            # TODO 增加一个自己的类别
            elif dataset_name is 'Sample':
    	        # 每一个类别点的数量
                num_per_class = np.array([4401119, 148313])
            weight = num_per_class / float(sum(num_per_class))
            ce_label_weight = 1 / (weight + 0.02)
            return np.expand_dims(ce_label_weight, axis=0)
    ...
    

训练

  1. main_Sample.py (拷贝 main_S3DIS.py)
from os.path import join, exists
from RandLANet import Network
from tester_Railway import ModelTester
from helper_ply import read_ply
from helper_tool import Plot
from helper_tool import DataProcessing as DP
from helper_tool import ConfigRailway as cfg
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
import pickle, argparse, os

class Railway:
    def __init__(self):
        self.name = 'Sample'
        # 最好给绝对路径
        self.path = '/home/ab/workspace/train/randla-net-tf2-main/data/sample'
        self.label_to_names = {0: 'background', 1: 'sample'}
        self.num_classes = len(self.label_to_names)
        self.label_values = np.sort([k for k, v in self.label_to_names.items()])
        self.label_to_idx = {l: i for i, l in enumerate(self.label_values)}
        # 如果想忽略背景类别 np.sort([0])
        #self.ignored_labels = np.sort([0]) # TODO
        self.ignored_labels = np.sort([]) # TODO

        self.original_folder = join(self.path, 'original_data')
        self.full_pc_folder = join(self.path, 'original_ply')
        self.sub_pc_folder = join(self.path, 'input_{:.3f}'.format(cfg.sub_grid_size))

        #训练、验证、测试数据都在original_data数据集中,需要做划分
        self.val_split = ["20240430205457370","20240430205527591"]  
        self.test_split= ["20240430205530638"]

        # Initial training-validation-testing files
        self.train_files = []
        self.val_files = []
        self.test_files = []
        cloud_names = [file_name[:-4] for file_name in os.listdir(self.original_folder) if file_name[-4:] == '.txt']
         #根据文件名划分训练、验证、测试数据集
        for pc_name in cloud_names:
            pc_file=join(self.sub_pc_folder, pc_name + '.ply')
            if pc_name in self.val_split:
                self.val_files.append(pc_file)
            elif pc_name in self.test_split:
                self.test_files.append(pc_file)
            else:
                self.train_files.append(pc_file)
        # Initiate containers
        self.val_proj = []
        self.val_labels = []
        self.test_proj = []
        self.test_labels = []

        self.possibility = {}
        self.min_possibility = {}
        self.class_weight = {}
        self.input_trees = {'training': [], 'validation': [], 'test': []}
        self.input_colors = {'training': [], 'validation': [], 'test': []}
        self.input_labels = {'training': [], 'validation': []}

        # Ascii files dict for testing
        self.ascii_files = {
            '20240430205530638.ply': '20240430205530638-reduced.labels'}

        self.load_sub_sampled_clouds(cfg.sub_grid_size)

    def load_sub_sampled_clouds(self, sub_grid_size):
        tree_path = join(self.path, 'input_{:.3f}'.format(sub_grid_size))
        files = np.hstack((self.train_files, self.val_files, self.test_files))
        for i, file_path in enumerate(files):
            cloud_name = file_path.split('/')[-1][:-4]
            print('Load_pc_' + str(i) + ': ' + cloud_name)
            if file_path in self.val_files:
                cloud_split = 'validation'
            elif file_path in self.train_files:
                cloud_split = 'training'
            else:
                cloud_split = 'test'

            # Name of the input files
            kd_tree_file = join(tree_path, '{:s}_KDTree.pkl'.format(cloud_name))
            sub_ply_file = join(tree_path, '{:s}.ply'.format(cloud_name))

            # read ply with data
            data = read_ply(sub_ply_file)
            sub_colors = np.vstack((data['red'], data['green'], data['blue'])).T
            if cloud_split == 'test':
                sub_labels = None
            else:
                sub_labels = data['class']

            # Read pkl with search tree
            with open(kd_tree_file, 'rb') as f:
                search_tree = pickle.load(f)

            self.input_trees[cloud_split] += [search_tree]
            self.input_colors[cloud_split] += [sub_colors]
            if cloud_split in ['training', 'validation']:
                self.input_labels[cloud_split] += [sub_labels]

        # Get validation and test re_projection indices
        print('\nPreparing reprojection indices for validation and test')

        for i, file_path in enumerate(files):

            # get cloud name and split
            cloud_name = file_path.split('/')[-1][:-4]

            # Validation projection and labels
            if file_path in self.val_files:
                proj_file = join(tree_path, '{:s}_proj.pkl'.format(cloud_name))
                with open(proj_file, 'rb') as f:
                    proj_idx, labels = pickle.load(f)
                self.val_proj += [proj_idx]
                self.val_labels += [labels]

            # Test projection
            if file_path in self.test_files:
                proj_file = join(tree_path, '{:s}_proj.pkl'.format(cloud_name))
                with open(proj_file, 'rb') as f:
                    proj_idx, labels = pickle.load(f)
                self.test_proj += [proj_idx]
                self.test_labels += [labels]
        print('finished')
        return

    # Generate the input data flow
    def get_batch_gen(self, split):
        if split == 'training':
            num_per_epoch = cfg.train_steps * cfg.batch_size
        elif split == 'validation':
            num_per_epoch = cfg.val_steps * cfg.val_batch_size
        elif split == 'test':
            num_per_epoch = cfg.val_steps * cfg.val_batch_size

        # Reset possibility
        self.possibility[split] = []
        self.min_possibility[split] = []
        self.class_weight[split] = []

        # Random initialize
        for i, tree in enumerate(self.input_trees[split]):
            self.possibility[split] += [np.random.rand(tree.data.shape[0]) * 1e-3]
            self.min_possibility[split] += [float(np.min(self.possibility[split][-1]))]

        if split != 'test':
            _, num_class_total = np.unique(np.hstack(self.input_labels[split]), return_counts=True)
            self.class_weight[split] += [np.squeeze([num_class_total / np.sum(num_class_total)], axis=0)]

        def spatially_regular_gen():
            # Generator loop
            for i in range(num_per_epoch):  # num_per_epoch
                # Choose the cloud with the lowest probability
                cloud_idx = int(np.argmin(self.min_possibility[split]))
                # choose the point with the minimum of possibility in the cloud as query point
                point_ind = np.argmin(self.possibility[split][cloud_idx])
                # Get all points within the cloud from tree structure
                points = np.array(self.input_trees[split][cloud_idx].data, copy=False)
                # print("points........." + str(points.shape))
                # Center point of input region
                center_point = points[point_ind, :].reshape(1, -1)
                # Add noise to the center point
                noise = np.random.normal(scale=cfg.noise_init / 10, size=center_point.shape)
                pick_point = center_point + noise.astype(center_point.dtype)
                query_idx = self.input_trees[split][cloud_idx].query(pick_point, k=cfg.num_points)[1][0]
                # Shuffle index
                query_idx = DP.shuffle_idx(query_idx)
                # Get corresponding points and colors based on the index
                queried_pc_xyz = points[query_idx]
                queried_pc_xyz[:, 0:2] = queried_pc_xyz[:, 0:2] - pick_point[:, 0:2]
                queried_pc_colors = self.input_colors[split][cloud_idx][query_idx]
                if split == 'test':
                    queried_pc_labels = np.zeros(queried_pc_xyz.shape[0])
                    queried_pt_weight = 1
                else:
                    queried_pc_labels = self.input_labels[split][cloud_idx][query_idx]
                    queried_pc_labels = np.array([self.label_to_idx[l] for l in queried_pc_labels])
                    queried_pt_weight = np.array([self.class_weight[split][0][n] for n in queried_pc_labels])

                # Update the possibility of the selected points
                dists = np.sum(np.square((points[query_idx] - pick_point).astype(np.float32)), axis=1)
                delta = np.square(1 - dists / np.max(dists)) * queried_pt_weight
                self.possibility[split][cloud_idx][query_idx] += delta
                self.min_possibility[split][cloud_idx] = float(np.min(self.possibility[split][cloud_idx]))
                if True:
                    yield (queried_pc_xyz,
                           queried_pc_colors.astype(np.float32),
                           queried_pc_labels,
                           query_idx.astype(np.int32),
                           np.array([cloud_idx], dtype=np.int32))
        gen_func = spatially_regular_gen
        gen_types = (tf.float32, tf.float32, tf.int32, tf.int32, tf.int32)
        gen_shapes = ([None, 3], [None, 3], [None], [None], [None])
        return gen_func, gen_types, gen_shapes

    def get_tf_mapping(self):
        # Collect flat inputs
        def tf_map(batch_xyz, batch_features, batch_labels, batch_pc_idx, batch_cloud_idx):
            batch_features = tf.map_fn(self.tf_augment_input, [batch_xyz, batch_features], dtype=tf.float32)
            input_points = []
            input_neighbors = []
            input_pools = []
            input_up_samples = []

            for i in range(cfg.num_layers):
                neigh_idx = tf.py_func(DP.knn_search, [batch_xyz, batch_xyz, cfg.k_n], tf.int32)
                sub_points = batch_xyz[:, :tf.shape(batch_xyz)[1] // cfg.sub_sampling_ratio[i], :]
                pool_i = neigh_idx[:, :tf.shape(batch_xyz)[1] // cfg.sub_sampling_ratio[i], :]
                up_i = tf.py_func(DP.knn_search, [sub_points, batch_xyz, 1], tf.int32)
                input_points.append(batch_xyz)
                input_neighbors.append(neigh_idx)
                input_pools.append(pool_i)
                input_up_samples.append(up_i)
                batch_xyz = sub_points

            input_list = input_points + input_neighbors + input_pools + input_up_samples
            input_list += [batch_features, batch_labels, batch_pc_idx, batch_cloud_idx]

            return input_list

        return tf_map

    # data augmentation
    @staticmethod
    def tf_augment_input(inputs):
        xyz = inputs[0]
        features = inputs[1]
        theta = tf.random_uniform((1,), minval=0, maxval=2 * np.pi)
        # Rotation matrices
        c, s = tf.cos(theta), tf.sin(theta)
        cs0 = tf.zeros_like(c)
        cs1 = tf.ones_like(c)
        R = tf.stack([c, -s, cs0, s, c, cs0, cs0, cs0, cs1], axis=1)
        stacked_rots = tf.reshape(R, (3, 3))

        # Apply rotations
        transformed_xyz = tf.reshape(tf.matmul(xyz, stacked_rots), [-1, 3])
        # Choose random scales for each example
        min_s = cfg.augment_scale_min
        max_s = cfg.augment_scale_max
        if cfg.augment_scale_anisotropic:
            s = tf.random_uniform((1, 3), minval=min_s, maxval=max_s)
        else:
            s = tf.random_uniform((1, 1), minval=min_s, maxval=max_s)

        symmetries = []
        for i in range(3):
            if cfg.augment_symmetries[i]:
                symmetries.append(tf.round(tf.random_uniform((1, 1))) * 2 - 1)
            else:
                symmetries.append(tf.ones([1, 1], dtype=tf.float32))
        s *= tf.concat(symmetries, 1)

        # Create N x 3 vector of scales to multiply with stacked_points
        stacked_scales = tf.tile(s, [tf.shape(transformed_xyz)[0], 1])

        # Apply scales
        transformed_xyz = transformed_xyz * stacked_scales

        noise = tf.random_normal(tf.shape(transformed_xyz), stddev=cfg.augment_noise)
        transformed_xyz = transformed_xyz + noise
        # rgb = features[:, :3]
        # stacked_features = tf.concat([transformed_xyz, rgb], axis=-1)
        return transformed_xyz

    def init_input_pipeline(self):
        print('Initiating input pipelines')
        cfg.ignored_label_inds = [self.label_to_idx[ign_label] for ign_label in self.ignored_labels]
        gen_function, gen_types, gen_shapes = self.get_batch_gen('training')
        gen_function_val, _, _ = self.get_batch_gen('validation')
        gen_function_test, _, _ = self.get_batch_gen('test')
        self.train_data = tf.data.Dataset.from_generator(gen_function, gen_types, gen_shapes)
        self.val_data = tf.data.Dataset.from_generator(gen_function_val, gen_types, gen_shapes)
        self.test_data = tf.data.Dataset.from_generator(gen_function_test, gen_types, gen_shapes)

        self.batch_train_data = self.train_data.batch(cfg.batch_size)
        self.batch_val_data = self.val_data.batch(cfg.val_batch_size)
        self.batch_test_data = self.test_data.batch(cfg.val_batch_size)
        map_func = self.get_tf_mapping()

        self.batch_train_data = self.batch_train_data.map(map_func=map_func)
        self.batch_val_data = self.batch_val_data.map(map_func=map_func)
        self.batch_test_data = self.batch_test_data.map(map_func=map_func)

        self.batch_train_data = self.batch_train_data.prefetch(cfg.batch_size)
        self.batch_val_data = self.batch_val_data.prefetch(cfg.val_batch_size)
        self.batch_test_data = self.batch_test_data.prefetch(cfg.val_batch_size)

        iter = tf.data.Iterator.from_structure(self.batch_train_data.output_types, self.batch_train_data.output_shapes)
        self.flat_inputs = iter.get_next()
        self.train_init_op = iter.make_initializer(self.batch_train_data)
        self.val_init_op = iter.make_initializer(self.batch_val_data)
        self.test_init_op = iter.make_initializer(self.batch_test_data)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--gpu', type=int, default=0, help='the number of GPUs to use [default: 0]')
    parser.add_argument('--mode', type=str, default='train', help='options: train, test, vis')
    parser.add_argument('--model_path', type=str, default='None', help='pretrained model path')
    FLAGS = parser.parse_args()

    GPU_ID = FLAGS.gpu
    os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
    os.environ['CUDA_VISIBLE_DEVICES'] = str(GPU_ID)
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

    Mode = FLAGS.mode
    dataset = Railway()
    dataset.init_input_pipeline()

    if Mode == 'train':
        model = Network(dataset, cfg)
        model.train(dataset)
    elif Mode == 'test':
        cfg.saving = False
        model = Network(dataset, cfg)
        if FLAGS.model_path is not 'None':
            chosen_snap = FLAGS.model_path
        else:
            chosen_snapshot = -1
            logs = np.sort([os.path.join('results', f) for f in os.listdir('results') if f.startswith('Log')])
            chosen_folder = logs[-1]
            snap_path = join(chosen_folder, 'snapshots')
            snap_steps = [int(f[:-5].split('-')[-1]) for f in os.listdir(snap_path) if f[-5:] == '.meta']
            chosen_step = np.sort(snap_steps)[-1]
            chosen_snap = os.path.join(snap_path, 'snap-{:d}'.format(chosen_step))
        print(".............. chosen_snap:" + chosen_snap)
        tester = ModelTester(model, dataset, restore_snap=chosen_snap)
        tester.test(model, dataset)

    else:
        ##################
        # Visualize data #
        ##################

        with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            sess.run(dataset.train_init_op)
            while True:
                flat_inputs = sess.run(dataset.flat_inputs)
                pc_xyz = flat_inputs[0]
                sub_pc_xyz = flat_inputs[1]
                labels = flat_inputs[21]
                Plot.draw_pc_sem_ins(pc_xyz[0, :, :], labels[0, :])
                Plot.draw_pc_sem_ins(sub_pc_xyz[0, :, :], labels[0, 0:np.shape(sub_pc_xyz)[1]])

  1. 开始训练 python main_Sample.py --mode train --gpu 0

参考

  1. https://github.com/QingyongHu/RandLA-Net
  2. https://blog.csdn.net/weixin_40653140/article/details/130285289

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA 安装BPMN插件-Activiti BPMN visualizer

IDEA安装BPMN插件 idea 18版本之前idea 18版本之后安装插件 推荐使用 Activiti BPMN visualizer插件注意 创建bpmn文件使用可视化面板 在可视化面板中右键可创建各种节点每个节点上都有连线 删除 设置的按钮 保存图片 idea 18版本之前 可以通过搜索插件actiBPMN直接安装 idea…

VBA代码解决方案第十四讲 如何利用VBA检查单元格中是否含有公式

《VBA代码解决方案》(版权10028096)这套教程是我最早推出的教程,目前已经是第三版修订了。这套教程定位于入门后的提高,在学习这套教程过程中,侧重点是要理解及掌握我的“积木编程”思想。要灵活运用教程中的实例像搭积木一样把自己喜欢的代码…

如何格式化只读U盘?

U盘只读无法格式化,该怎么处理?别担心!本文将向你提供一些实用方法,助你解决U盘写保护的难题。这些方法能有效帮助你解除U盘的只读状态,从而可以顺利进行格式化和其他操作。 不能格式化只读U盘 “我购买了一个U盘&…

64位和32位对C++ 对long类型的使用造成程序崩溃、内存泄漏问题。

系列文章目录 1、理解32位和64位下long类型和int类型不同 2、理解release和debug版本编译的可执行程序的区别 3、谨慎在64位下对long类型与int类型去赋值和相互转换 文章目录 系列文章目录前言一、int、long类型二、使用步骤1.示例代码 前言 编译环境:qt -c、linu…

代码随想录算法训练营第三十二 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 讲解链接:https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html 简单思路:逐个计算连续两天的股票差值,sum初始为零&…

SAP 物料的与压缩库存数据不一致

在测试系统中进行501和561增加库存的时候,系统提示物料的预压缩库存数据不一致的报错。 如下图所示: 首先想到的就是搜SAP的NOTES,找到了相关的两个note:293356 note:2197042 表示:数据库表 ACDOCA 和 ACDOCA_M_EXTRACT 之间的差异。 经过查询发现是由于物料分类账中的…

平衡二叉树的应用举例

AVL 是一种自平衡二叉搜索树,其中任何节点的左右子树的高度之差不能超过 1。 AVL树的特点: 1、它遵循二叉搜索树的一般属性。 2、树的每个子树都是平衡的,即左右子树的高度之差最多为1。 3、当插入新节点时,树会自我平衡。因此…

第N3周:Pytorch文本分类入门

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 目录 本周任务: 文本分类流程图: 需要的环境: 数据集: TextClassificationModel模型介绍&#xff1a…

Java基础语法——字符串(String/StringBuilder/Stringjoiner)

String Java的String类是不可变的,意味着一旦创建,其值就不能被改变。String类提供了丰富的API来操作字符串。 以下是一些常用的方法: 构造方法: 有以下几种常见的: public class stringlearn {public static void…

民国漫画杂志《时代漫画》第34期.PDF

时代漫画34.PDF: https://url03.ctfile.com/f/1779803-1248636026-7e46c5?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

flume-ng-sql | 支持JDK8+ | 支持Flume 1.11.0 | 使用 Kotlin 编写

文章目录 简介用法 简介 flume-ng-sql-source 作者已经停止维护了,并且已经不支持新版Flume,我们决定开启这一项目 flume-ng-sql。 用法 像 flume-ng-sql-source 一样将 flume-ng-sql 发行的 Jar 包导入lib下,必要时需要添加自己 MySQL 版本…

IMU状态预积分代码实现 —— IMU状态预积分类

IMU状态预积分代码实现 —— IMU状态预积分类 实现IMU状态预积分类 实现IMU状态预积分类 首先,实现预积分自身的结构。一个预积分类应该存储一下数据: 预积分的观测量 △ R ~ i j , △ v ~ i j , △ p ~ i j \bigtriangleup \tilde{R} _{ij},\bigtrian…

【Python爬虫--scrapy+selenium框架】超详细的Python爬虫scrapy+selenium框架学习笔记(保姆级别的,非常详细)

六,selenium 想要下载PDF或者md格式的笔记请点击以下链接获取 python爬虫学习笔记点击我获取 Scrapyselenium详细学习笔记点我获取 Python超详细的学习笔记共21万字点我获取 1,下载配置 ## 安装: pip install selenium## 它与其他库不同…

【C++】C++11新特性:列表初始化、声明、新容器、右值引用、万能引用和完美转发

目录 一、列表初始化 1.1 { } 初始化 1.2 std::initializer_list 二、声明 2.1 auto 2.2 decltype 2.3 nullptr 三、新容器 四、右值引用和移动语义 4.1 左值和左值引用 4.2 右值和右值引用 4.3 左值引用与右值引用比较 4.4 右值引用使用场景和意义:移…

AI能否代替ACE

什么是ACE ? 申请ACE需要以下条件: 1.发表与oracle相关的技术博客 2.参与Oracle相关的技术大会 3.对Oracle社区做出贡献。 这正好是AI应用的场景吗? 在一个群里有个群友质疑AI落地,以及应用领域? Kelvin:我一直在迷茫,学不好。这么多有趣AI 问题&…

冯喜运:5.31晚间黄金原油行情分析及尾盘操作策略

【黄金消息面分析】:周五(5月31日),最新发布的数据显示,美国4月核心PCE物价指数月率录得0.2%,低于预期(0.3%),经济学家认为,核心指数比整体指数更能反映通胀。除此之外,美…

[openwrt-21.02]openwrt-21.02 make menuconfig不显示luci-app-firewall问题分析及解决方案

问题描述 make menuconfig在 在applications界面没有luci-app-firewall 问题分析 首先重新执行 ./scripts/feeds update -a ./scripts/feeds install -a 然后再次执行make menuconfig,依然不显示,所以不是feeds安装的问题 最后看到log有个openmptc…

P3881

最小值最大 二分:枚举两个牛之间的最小距离,左端点是1,右端点是篱笆总长度。 Check数组: 如果两头牛之间距离是Mid不合法,则返回0(false); 如果两头牛之间距离是Mid合法&#xf…

Beamer中二阶导、一阶导数的显示问题

Beamer中二阶导、一阶导数的显示问题 在beamer中表示 f ′ f f′和 f ′ ′ f f′′时发现导数符号距离 f f f很近 \documentclass{beamer} \usepackage{amsmath,amssymb}\begin{document} \begin{frame}\frametitle{Derivative}Derivative:\[f^{\prime}(x) \quad f \quad…

基于安卓的虫害识别软件设计--(1)模型训练与可视化

引言 简介:使用pytorch框架,从模型训练、模型部署完整地实现了一个基础的图像识别项目计算资源:使用的是Kaggle(每周免费30h的GPU) 1.创建名为“utils_1”的模块 模块中包含:训练和验证的加载器函数、训练…