【代码解读】OpenCOOD框架之model模块(以PointPillarFCooper为例)

point_pillar_fcooper

  • PointPillarFCooper
  • PointPillars
    • PillarVFE
    • PFNLayer
    • PointPillarScatter
    • BaseBEVBackbone
    • DownsampleConv
      • DoubleConv
  • SpatialFusion
  • 检测头

(紧扣PointPillarFCooper的框架结构,一点一点看代码)

PointPillarFCooper

# -*- coding: utf-8 -*-
# Author: Runsheng Xu <rxx3386@ucla.edu>
# License: TDG-Attribution-NonCommercial-NoDistrib
import pprint

import torch.nn as nn

from opencood.models.sub_modules.pillar_vfe import PillarVFE
from opencood.models.sub_modules.point_pillar_scatter import PointPillarScatter
from opencood.models.sub_modules.base_bev_backbone import BaseBEVBackbone
from opencood.models.sub_modules.downsample_conv import DownsampleConv
from opencood.models.sub_modules.naive_compress import NaiveCompressor
from opencood.models.fuse_modules.f_cooper_fuse import SpatialFusion


class PointPillarFCooper(nn.Module):
    """
    F-Cooper implementation with point pillar backbone.
    """
    def __init__(self, args):
        super(PointPillarFCooper, self).__init__()
        print("args: ")
        pprint.pprint(args)
        self.max_cav = args['max_cav']
        # PIllar VFE Voxel Feature Encoding
        self.pillar_vfe = PillarVFE(args['pillar_vfe'],
                                    num_point_features=4,
                                    voxel_size=args['voxel_size'],
                                    point_cloud_range=args['lidar_range'])
        self.scatter = PointPillarScatter(args['point_pillar_scatter'])
        self.backbone = BaseBEVBackbone(args['base_bev_backbone'], 64)
        # used to downsample the feature map for efficient computation
        self.shrink_flag = False
        if 'shrink_header' in args:
            self.shrink_flag = True
            self.shrink_conv = DownsampleConv(args['shrink_header'])
        self.compression = False

        if args['compression'] > 0:
            self.compression = True
            self.naive_compressor = NaiveCompressor(256, args['compression'])

        self.fusion_net = SpatialFusion()

        self.cls_head = nn.Conv2d(128 * 2, args['anchor_number'],
                                  kernel_size=1)
        self.reg_head = nn.Conv2d(128 * 2, 7 * args['anchor_number'],
                                  kernel_size=1)

        if args['backbone_fix']:
            self.backbone_fix()

  • args: 其实就是从hypes_yaml配置文件里传来的参数
args:
{'anchor_number': 2,
 'backbone_fix': False,
 'base_bev_backbone': {'layer_nums': [3, 5, 8],
                       'layer_strides': [2, 2, 2],
                       'num_filters': [64, 128, 256],
                       'num_upsample_filter': [128, 128, 128],
                       'upsample_strides': [1, 2, 4]},
 'compression': 0,
 'lidar_range': [-140.8, -40, -3, 140.8, 40, 1],
 'max_cav': 5,
 'pillar_vfe': {'num_filters': [64],
                'use_absolute_xyz': True,
                'use_norm': True,
                'with_distance': False},
 'point_pillar_scatter': {'grid_size': array([704, 200,   1], dtype=int64),
                          'num_features': 64},
 'shrink_header': {'dim': [256],
                   'input_dim': 384,
                   'kernal_size': [1],
                   'padding': [0],
                   'stride': [1]},
 'voxel_size': [0.4, 0.4, 4]}

    def backbone_fix(self):
        """
        Fix the parameters of backbone during finetune on timedelay。
        """
        for p in self.pillar_vfe.parameters():
            p.requires_grad = False

        for p in self.scatter.parameters():
            p.requires_grad = False

        for p in self.backbone.parameters():
            p.requires_grad = False

        if self.compression:
            for p in self.naive_compressor.parameters():
                p.requires_grad = False
        if self.shrink_flag:
            for p in self.shrink_conv.parameters():
                p.requires_grad = False

        for p in self.cls_head.parameters():
            p.requires_grad = False
        for p in self.reg_head.parameters():
            p.requires_grad = False

backbone_fix 方法用于在模型微调过程中固定骨干网络的参数,以避免它们被更新。
遍历了模型中各个需要固定参数的组件,并将它们的 requires_grad 属性设置为 False,这意味着这些参数不会被优化器更新。
我们来看 forward 方法:

    def forward(self, data_dict):
        voxel_features = data_dict['processed_lidar']['voxel_features']
        voxel_coords = data_dict['processed_lidar']['voxel_coords']
        voxel_num_points = data_dict['processed_lidar']['voxel_num_points']
        record_len = data_dict['record_len']

        batch_dict = {'voxel_features': voxel_features,
                      'voxel_coords': voxel_coords,
                      'voxel_num_points': voxel_num_points,
                      'record_len': record_len}
        # n, 4 -> n, c
        batch_dict = self.pillar_vfe(batch_dict)
        # n, c -> N, C, H, W
        batch_dict = self.scatter(batch_dict)
        batch_dict = self.backbone(batch_dict)

        spatial_features_2d = batch_dict['spatial_features_2d']
        # downsample feature to reduce memory
        if self.shrink_flag:
            spatial_features_2d = self.shrink_conv(spatial_features_2d)
        # compressor
        if self.compression:
            spatial_features_2d = self.naive_compressor(spatial_features_2d)

        fused_feature = self.fusion_net(spatial_features_2d, record_len)

        psm = self.cls_head(fused_feature)
        rm = self.reg_head(fused_feature)

        output_dict = {'psm': psm,
                       'rm': rm}

        return output_dict

forward 方法定义了模型的前向传播过程。它接受一个数据字典作为输入,包含了经过处理的点云数据。
首先,从输入字典中提取出点云特征、体素坐标、体素点数等信息。
然后,依次将数据通过 pillar_vfe、scatter 和 backbone 这几个模块进行处理,得到了一个包含了空间特征的张量 spatial_features_2d。
如果启用了特征图的下采样(shrink_flag 为 True),则对 spatial_features_2d 进行下采样。
如果启用了特征压缩(compression 为 True),则对 spatial_features_2d 进行压缩。
最后,将压缩后的特征通过 fusion_net 进行融合,并通过 cls_head 和 reg_head 进行分类和回归,得到预测结果。
整个 forward 方法实现了模型的数据流动过程,从输入数据到最终输出结果的计算过程。

  • PointPillarsFcooper结构
PointPillarFCooper(
  (pillar_vfe): PillarVFE(
    (pfn_layers): ModuleList(
      (0): PFNLayer(
        (linear): Linear(in_features=10, out_features=64, bias=False)
        (norm): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      )
    )
  )
  (scatter): PointPillarScatter()
  (backbone): BaseBEVBackbone(
    (blocks): ModuleList(
      (0): Sequential(
        (0): ZeroPad2d(padding=(1, 1, 1, 1), value=0.0)
        (1): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), bias=False)
        (2): BatchNorm2d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (3): ReLU()
        (4): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (5): BatchNorm2d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (6): ReLU()
        (7): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (8): BatchNorm2d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (9): ReLU()
        (10): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (11): BatchNorm2d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (12): ReLU()
      )
      (1): Sequential(
        (0): ZeroPad2d(padding=(1, 1, 1, 1), value=0.0)
        (1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), bias=False)
        (2): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (3): ReLU()
        (4): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (5): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (6): ReLU()
        (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (8): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (9): ReLU()
        (10): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (11): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (12): ReLU()
        (13): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (14): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (15): ReLU()
        (16): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (17): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (18): ReLU()
      )
      (2): Sequential(
        (0): ZeroPad2d(padding=(1, 1, 1, 1), value=0.0)
        (1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), bias=False)
        (2): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (3): ReLU()
        (4): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (5): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (6): ReLU()
        (7): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (8): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (9): ReLU()
        (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (11): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (12): ReLU()
        (13): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (14): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (15): ReLU()
        (16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (17): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (18): ReLU()
        (19): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (20): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (21): ReLU()
        (22): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (23): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (24): ReLU()
        (25): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (26): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (27): ReLU()
      )
    )
    (deblocks): ModuleList(
      (0): Sequential(
        (0): ConvTranspose2d(64, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
        (1): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (2): ReLU()
      )
      (1): Sequential(
        (0): ConvTranspose2d(128, 128, kernel_size=(2, 2), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (2): ReLU()
      )
      (2): Sequential(
        (0): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(4, 4), bias=False)
        (1): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
        (2): ReLU()
      )
    )
  )
  (shrink_conv): DownsampleConv(
    (layers): ModuleList(
      (0): DoubleConv(
        (double_conv): Sequential(
          (0): Conv2d(384, 256, kernel_size=(1, 1), stride=(1, 1))
          (1): ReLU(inplace=True)
          (2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
          (3): ReLU(inplace=True)
        )
      )
    )
  )
  (fusion_net): SpatialFusion()
  (cls_head): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
  (reg_head): Conv2d(256, 14, kernel_size=(1, 1), stride=(1, 1))
)

PointPillars

在这里插入图片描述
网络overview:网络的主要组成部分是PFN、Backbone和 SSD 检测头。原始点云被转换为堆叠的柱子张量和柱子索引张量。编码器使用堆叠的柱子来学习一组特征,这些特征可以分散回卷积神经网络的 2D 伪图像。检测头使用来自主干的特征来预测对象的 3D 边界框。请注意:在这里,我们展示了汽车网络的骨干维度。

PillarVFE

就是 voxel feature encoder:先对点云进行特征提取
VFE由PFNLayer(Pillar Feature Net)组成

  • model_cfg
{'num_filters': [64],
 'use_absolute_xyz': True,
  'use_norm': True,
  'with_distance': False},
class PillarVFE(nn.Module):
    def __init__(self, model_cfg, num_point_features, voxel_size,
                 point_cloud_range):
        super().__init__()
        self.model_cfg = model_cfg

        self.use_norm = self.model_cfg['use_norm']
        self.with_distance = self.model_cfg['with_distance']

        self.use_absolute_xyz = self.model_cfg['use_absolute_xyz']
        num_point_features += 6 if self.use_absolute_xyz else 3
        if self.with_distance:
            num_point_features += 1

        self.num_filters = self.model_cfg['num_filters']
        assert len(self.num_filters) > 0
        num_filters = [num_point_features] + list(self.num_filters)

        pfn_layers = []
        for i in range(len(num_filters) - 1):
            in_filters = num_filters[i]
            out_filters = num_filters[i + 1]
            pfn_layers.append(
                PFNLayer(in_filters, out_filters, self.use_norm,
                         last_layer=(i >= len(num_filters) - 2))
            )
        self.pfn_layers = nn.ModuleList(pfn_layers)

        self.voxel_x = voxel_size[0]
        self.voxel_y = voxel_size[1]
        self.voxel_z = voxel_size[2]
        self.x_offset = self.voxel_x / 2 + point_cloud_range[0]
        self.y_offset = self.voxel_y / 2 + point_cloud_range[1]
        self.z_offset = self.voxel_z / 2 + point_cloud_range[2]

PFNLayer

这里只是一个全连接+归一化(好像和原来的算法有出入)

class PFNLayer(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels,
                 use_norm=True,
                 last_layer=False):
        super().__init__()

        self.last_vfe = last_layer
        self.use_norm = use_norm
        if not self.last_vfe:
            out_channels = out_channels // 2

        if self.use_norm:
            self.linear = nn.Linear(in_channels, out_channels, bias=False)
            self.norm = nn.BatchNorm1d(out_channels, eps=1e-3, momentum=0.01)
        else:
            self.linear = nn.Linear(in_channels, out_channels, bias=True)

        self.part = 50000

PointPillarScatter

主要作用就是三维点云压缩成bev(鸟瞰图)

class PointPillarScatter(nn.Module):
    def __init__(self, model_cfg):
        super().__init__()

        self.model_cfg = model_cfg
        self.num_bev_features = self.model_cfg['num_features']
        self.nx, self.ny, self.nz = model_cfg['grid_size']
        assert self.nz == 1
  • model_cfg:
{'grid_size': array([704, 200,   1], dtype=int64),
 'num_features': 64}

BaseBEVBackbone

参考这个图
在这里插入图片描述
3 * Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

5 * Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

8 * Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

3、5、8对应着layer_nums

  • model_cfg
{'layer_nums': [3, 5, 8],
 'layer_strides': [2, 2, 2],
 'num_filters': [64, 128, 256],
 'num_upsample_filter': [128, 128, 128],
 'upsample_strides': [1, 2, 4]},
class BaseBEVBackbone(nn.Module):
    def __init__(self, model_cfg, input_channels):
        super().__init__()
        self.model_cfg = model_cfg

        if 'layer_nums' in self.model_cfg:

            assert len(self.model_cfg['layer_nums']) == \
                   len(self.model_cfg['layer_strides']) == \
                   len(self.model_cfg['num_filters'])

            layer_nums = self.model_cfg['layer_nums']
            layer_strides = self.model_cfg['layer_strides']
            num_filters = self.model_cfg['num_filters']
        else:
            layer_nums = layer_strides = num_filters = []

        if 'upsample_strides' in self.model_cfg:
            assert len(self.model_cfg['upsample_strides']) \
                   == len(self.model_cfg['num_upsample_filter'])

            num_upsample_filters = self.model_cfg['num_upsample_filter']
            upsample_strides = self.model_cfg['upsample_strides']

        else:
            upsample_strides = num_upsample_filters = []

        num_levels = len(layer_nums)   # len(layer_nums)个Sequential
        c_in_list = [input_channels, *num_filters[:-1]]

        self.blocks = nn.ModuleList()
        self.deblocks = nn.ModuleList()

        for idx in range(num_levels):
            cur_layers = [
                nn.ZeroPad2d(1),
                nn.Conv2d(
                    c_in_list[idx], num_filters[idx], kernel_size=3,
                    stride=layer_strides[idx], padding=0, bias=False
                ),
                nn.BatchNorm2d(num_filters[idx], eps=1e-3, momentum=0.01),
                nn.ReLU()
            ]
            for k in range(layer_nums[idx]):  # 每个Sequential里有多少个以下结构
                cur_layers.extend([
                    nn.Conv2d(num_filters[idx], num_filters[idx],
                              kernel_size=3, padding=1, bias=False),
                    nn.BatchNorm2d(num_filters[idx], eps=1e-3, momentum=0.01),
                    nn.ReLU()
                ])

            self.blocks.append(nn.Sequential(*cur_layers))
            # 以下是deblock模块
            if len(upsample_strides) > 0:
                stride = upsample_strides[idx]
                if stride >= 1:
                    self.deblocks.append(nn.Sequential(
                        nn.ConvTranspose2d(
                            num_filters[idx], num_upsample_filters[idx],
                            upsample_strides[idx],
                            stride=upsample_strides[idx], bias=False
                        ),
                        nn.BatchNorm2d(num_upsample_filters[idx],
                                       eps=1e-3, momentum=0.01),
                        nn.ReLU()
                    ))
                else:
                    stride = np.round(1 / stride).astype(np.int)
                    self.deblocks.append(nn.Sequential(
                        nn.Conv2d(
                            num_filters[idx], num_upsample_filters[idx],
                            stride,
                            stride=stride, bias=False
                        ),
                        nn.BatchNorm2d(num_upsample_filters[idx], eps=1e-3,
                                       momentum=0.01),
                        nn.ReLU()
                    ))

        c_in = sum(num_upsample_filters)
        if len(upsample_strides) > num_levels:
            self.deblocks.append(nn.Sequential(
                nn.ConvTranspose2d(c_in, c_in, upsample_strides[-1],
                                   stride=upsample_strides[-1], bias=False),
                nn.BatchNorm2d(c_in, eps=1e-3, momentum=0.01),
                nn.ReLU(),
            ))

        self.num_bev_features = c_in

DownsampleConv

其实就是下采样(用了几个DoubleConv)
主要作用就是

  • 降低计算成本: 在深度神经网络中,参数量和计算量通常会随着输入数据的尺寸增加而增加。通过下采样,可以降低每个层的输入数据的尺寸,从而降低网络的计算成本。
  • 减少过拟合: 下采样可以通过减少输入数据的维度和数量来减少模型的复杂性,从而有助于降低过拟合的风险。过拟合是指模型在训练数据上表现良好,但在测试数据上表现较差的现象。
  • 提高模型的泛化能力: 通过减少输入数据的空间分辨率,下采样有助于模型学习更加抽象和通用的特征,从而提高了模型对于不同数据的泛化能力。
  • 加速训练和推理过程: 由于下采样可以降低网络的计算成本,因此可以加快模型的训练和推理过程。这对于处理大规模数据和实时应用特别有用。
class DownsampleConv(nn.Module):
    def __init__(self, config):
        super(DownsampleConv, self).__init__()
        self.layers = nn.ModuleList([])
        input_dim = config['input_dim']

        for (ksize, dim, stride, padding) in zip(config['kernal_size'],
                                                 config['dim'],
                                                 config['stride'],
                                                 config['padding']):
            self.layers.append(DoubleConv(input_dim,
                                          dim,
                                          kernel_size=ksize,
                                          stride=stride,
                                          padding=padding))
            input_dim = dim

config参数

{'dim': [256],
 'input_dim': 384,
 'kernal_size': [1],
 'padding': [0],
 'stride': [1]},

DoubleConv

其实就是两层卷积

class DoubleConv(nn.Module):
    """
    Double convoltuion
    Args:
        in_channels: input channel num
        out_channels: output channel num
    """

    def __init__(self, in_channels, out_channels, kernel_size,
                 stride, padding):
        super().__init__()
        self.double_conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size,
                      stride=stride, padding=padding),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
            nn.ReLU(inplace=True)
        )

SpatialFusion

其实就是取最大来进行融合特征
在这里插入图片描述

class SpatialFusion(nn.Module):
    def __init__(self):
        super(SpatialFusion, self).__init__()

    def regroup(self, x, record_len):
        cum_sum_len = torch.cumsum(record_len, dim=0)
        split_x = torch.tensor_split(x, cum_sum_len[:-1].cpu())
        return split_x

    def forward(self, x, record_len):
        # x: B, C, H, W, split x:[(B1, C, W, H), (B2, C, W, H)]
        split_x = self.regroup(x, record_len)
        out = []

        for xx in split_x:
            xx = torch.max(xx, dim=0, keepdim=True)[0]
            out.append(xx)
        return torch.cat(out, dim=0)

检测头

(cls_head): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
(reg_head): Conv2d(256, 14, kernel_size=(1, 1), stride=(1, 1))

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

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

相关文章

在两台CentOS 7服务器上部署MinIO集群---准确

环境说明&#xff1a; 2台Centos7服务器 IP地址分别为172.16.1.9和172.16.1.10 1. 创建minio用户和目录 在两台服务器上执行以下命令&#xff1a; sudo useradd -m -d /app/minio minio sudo mkdir -p /app/minioData sudo mkdir -p /app/minio/logs sudo chown -R mini…

数据结构与算法(数组,栈,队列,链表,哈希表,搜索算法,排序算法,查找算法,策略算法,递归算法,二叉搜索树BST,动态规划算法)

文章目录 1 课程介绍1.1 前置知识1.2 为什么要学习算法1.3 大厂面试常见数据结构题目(基础)1.4 数据结构和算法的关系 2 数据结构2.1 数据结构概述2.1.1 数据结构是什么2.1.2 数据结构分类2.1.2.1 线性结构2.1.2.2 非线性结构2.1.2.3 小总结 2.1.3 数据结构范围 2.2 数组Array2…

leetcode 2.27

leetcode hot 100 哈希1.字母异位词分组2.最长连续序列 双指针1.盛最多水的容器2.和为 K 的子数组 数组1.除自身以外数组的乘积 哈希 1.字母异位词分组 49. 字母异位词分组 方法一&#xff1a;排序 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符…

Redis之一: 简介及环境安装搭建

什么是NoSQL? NoSQL&#xff0c;指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写&#xff0c;是对不同于传统的关系型数据库的数据库管理系统的统称。 NoSQL用于超大规模数据的存储。&#xff08;例如谷歌或Facebook每天为他们的用户收集万亿比特的数据&#xf…

python:时间序列谐波拟合与残差分析(利用最小二乘法确定模型参数)

作者&#xff1a;CSDN _养乐多_ 在科学研究中&#xff0c;经常需要对实验数据进行拟合&#xff0c;以找出其中的规律。本文介绍了如何使用Python中的NumPy、Matplotlib和SciPy库进行谐波拟合&#xff0c;并对拟合结果进行残差分析。 从下图可以看出&#xff0c;谐波拟合曲线…

Python算法100例-2.6 分糖果

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序6.运行结果 1&#xff0e;问题描述 10个小孩围成一圈分糖果&#xff0c;老师分给第1个小孩10块&#xff0c;第2个小孩2块&#xff0c;第3个小孩8块&…

C#,弗洛伊德-瑞文斯特(Floyd-Rivest)算法与源代码

Robert W. Floyd 1 Floyd-Rivest 算法 Floyd-Rivest 算法是一种选择算法&#xff0c;用于在不同元素的数组中找到第k个最小元素。它类似于快速选择算法&#xff0c;但在实际运行中有更好的运行时间。 和 QuickSelect 一样&#xff0c;该算法基于分区的思想工作。对数组进行分…

istio学习记录——VirtualService详解

上一篇使用VirtualService进行了简单的流量控制&#xff0c;并通过Gateway将流量导入到了集群内。这一篇将更加深入的介绍 VirtualService。 k8s中有service&#xff0c;service能够对流量进行负载均衡&#xff0c;那为什么istio又引入了VirtualService呢&#xff0c;因为serv…

最新IE跳转Edge浏览器解决办法(2024.2.26)

最新IE跳转Edge浏览器解决办法&#xff08;2024.2.26&#xff09; 1. IE跳转原因1.1. 原先解决办法1.2. 最新解决办法1.3. 最后 1. IE跳转原因 关于IE跳转问题是由于在2023年2月14日&#xff0c;微软正式告别IE浏览器&#xff0c;导致很多使用Windows10系统的电脑在打开IE浏览…

300分钟吃透分布式缓存-17讲:如何理解、选择并使用Redis的核心数据类型?

Redis 数据类型 首先&#xff0c;来看一下 Redis 的核心数据类型。Redis 有 8 种核心数据类型&#xff0c;分别是 &#xff1a; & string 字符串类型&#xff1b; & list 列表类型&#xff1b; & set 集合类型&#xff1b; & sorted set 有序集合类型&…

多线程与高并发(1)- 线程基础、并发特性、锁、JUC工具

文章目录 第一章、线程基础知识一、基础概念1、什么是程序&#xff1f;2、什么是进程&#xff1f;3、什么是线程&#xff1f;4、什么是线程的切换&#xff08;Context Switch&#xff09;&#xff1f;5、单核CPU 设定多线程是否有意义&#xff1f;6、工作线程数是不是设置的越大…

【Linux】部署单机项目(自动化启动)---(图文并茂详细讲解)

目录 一 准备工作 1.1 连接服务器拷贝文件 1.2 解压 二 JDK安装 2.1 配置坏境变量 2.2 查看版本 三 Tomcat(自启动) 3.1 复制启动命令的位置 3.2 添加命令相关配置文件 3.2.1 配置jdk及tomcat目录 3.2.2 添加优先级 3.3 设置自启动命令 3.4 开放端口 四 My…

行业交流 | “建筑工业化—创新型建筑技术的应用”主题沙龙

11月9日下午&#xff0c;由环同济知识经济圈发展推进领导小组办公室指导&#xff0c;上海市杨浦区科委、同济科技园核心园、同济EMBA设计协会联合主办&#xff0c;环同济发展促进会协办的“建筑工业化——创新型建筑技术的应用”主题沙龙在我园区顺利举办。优积建筑科技发展(上…

32单片机基础:TIM定时中断

STM32中功能最强大&#xff0c;结构最复杂的一个外设——定时器 因为定时器的内容很多&#xff0c;所以本大节总共分为4个部分&#xff0c;8小节。 第一部分&#xff1a;主要讲定时器基本的定时功能,也就是定一个时间&#xff0c;然后让定时器每隔这个时间产生一个中断&#…

鸿蒙ArkTs开发WebView问题总结

1. 加载WebView页面报错"Can not read properties of null (reading getltem)" 解决: 在加载webview的controller中加入.domStorageAccess(true) build() {Column() {Row().width(100%).height(50rpx)Web({ src: src, controller: this.controller }).javaScriptAc…

【2.3深度学习开发任务实例】(1)神经网络模型的特点【大厂AI课学习笔记】

从本章开始&#xff0c;我把标题的顺序变了一下&#xff0c;大厂AI课笔记&#xff0c;放到后面。因为我发现App上&#xff0c;标题无法显示完全。 从本章开始&#xff0c;要学习深度学习开发任务的全部过程了。 我们将通过小汽车识别赛道上的标志牌&#xff0c;给出检测框&am…

Leetcoder Day25| 回溯part05:子集+排列

491.递增子序列 给定一个整型数组, 你的任务是找到所有该数组的递增子序列&#xff0c;递增子序列的长度至少是2。 示例: 输入:[4, 7, 6, 7]输出: [[4, 6], [4, 7], [4, 6, 7], [6, 7], [7,7], [4,7,7]] 说明: 给定数组的长度不会超过15。数组中的整数范围是 [-100,100]。给定数…

Camtasia 2023 v23.4.2.51146 (x64) 中文激活授权版(附安装教程+激活补丁) 喀秋莎(屏幕录制剪辑) 常用快捷键

目录 功能特性 常用快捷键 一、关于文件设置 二、关于编辑设置 三、关于视图设置 四、关于录制设置 破解说明 Camtasia 2023免费版是一款由TechSmith公司官方进行汉化推出的最新版本&#xff0c;该软件集屏幕录制和视频剪辑功能于一体的软件&#xff0c;提供屏幕录制、区域录…

Maya笔记 设置工作目录

Maya会把素材场景等自动保存在工作目录里&#xff0c;我们可以自己定义工作目录 步骤1 创建workspace.mel文件 文件/设置项目 ——>选择一个文件夹&#xff0c;点击设置——>创建默认工作区 这一个后&#xff0c;可以在文件夹里看到.mel文件 步骤2 自动创建文件夹…

Groovy(第九节) Groovy 之单元测试

JUnit 利用 Java 对 Song 类进行单元测试 默认情况下 Groovy 编译的类属性是私有的,所以不能直接在 Java 中访问它们,必须像下面这样使用 setter: 编写这个测试用例余下的代码就是小菜一碟了。测试用例很好地演示了这样一点:用 Groovy 所做的一切都可以轻易地在 Java 程序…