Faster RCNN网络源码解读(Ⅳ) --- Faster R-CNN主体代码执行流程解析

news2024/11/16 18:57:27

目录

一、Faster R-CNN框架图

二、结合代码 (faster_rcnn_framework.py)

2.1 FasterRCNNBase类

2.2 FasterRCNN类 


一、Faster R-CNN框架图

        我们获取一张图片后将其输入特征提取网络Backbone中得到特征图,将特征图输入到RPN中得到一系列的proposal即目标建议框(2K左右),将建议框根据原图和特征图的投影关系可以得到一个个特征矩阵,将每个特征矩阵输入到ROIpooling层会得到一些大小相同的特征图(7*7),接着对他们进行展平处理,通过两个全连接层再通过类别预测层和边界框回归层进行后处理......

二、结合代码 (faster_rcnn_framework.py)

2.1 FasterRCNNBase类

        我们来看FasterRCNNBase这个类,在它的初始化函数中,我们传入如下参数:

	# self 特征提取网络 区域建议生成网络 (三部分)
	# backbone就是图像中特征提取网络部分
	# rpn也是图中的一部分(区域建议生成网络部分)
	# roi_heads除了最后一步的所有
    def __init__(self, backbone, rpn, roi_heads, transform):
        super(FasterRCNNBase, self).__init__()
        self.transform = transform
        self.backbone = backbone
        self.rpn = rpn
        self.roi_heads = roi_heads
        # used only on torchscript mode
        self._has_warned = False

        正向传播过程:


	#注意:这里输入的images的大小都是不同的。后面会进行预处理将这些图片放入同样大小的tensor中打包成一个batch
	#正向传播过程 params :预测的图片,为List[Tensor]型 
	#image和target我们再word上面有标注
    def forward(self, images, targets=None):
        # type: (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]
        """
        Arguments:
            images (list[Tensor]): images to be processed
            targets (list[Dict[Tensor]]): ground-truth boxes present in the image (optional)

        Returns:
            result (list[BoxList] or dict[Tensor]): the output from the model.
                During training, it returns a dict[Tensor] which contains the losses.
                During testing, it returns list[BoxList] contains additional fields
                like `scores`, `labels` and `mask` (for Mask R-CNN models).

        """
		#判断是否是训练模式,若是训练模式一定要有targets,若targets为空,抛出异常
        if self.training and targets is None:
            raise ValueError("In training mode, targets should be passed")

		#检查标注框是否有错误
        if self.training:
            assert targets is not None
            for target in targets:         # 进一步判断传入的target的boxes参数是否符合规定
                boxes = target["boxes"]
				#判断boxes是不是torch.Tensor的格式
                if isinstance(boxes, torch.Tensor):
					#shape对应的目标有几个,毕竟一个目标就对应一个边界框嘛
					#box的第一个维度是N表示图像中有几个边界框 第二个维度是4(xminxmax..)
					#即如果最后一个维度!=4也要报错
                    if len(boxes.shape) != 2 or boxes.shape[-1] != 4:
                        raise ValueError("Expected target boxes to be a tensor"
                                         "of shape [N, 4], got {:}.".format(
                                          boxes.shape))
                else:
                    raise ValueError("Expected target boxes to be of type "
                                     "Tensor, got {:}.".format(type(boxes)))

 
		#存储每张图片的原始尺寸 定义是个List类型 每个list又是个元组类型 元组里面存放着图片的长宽
		original_image_sizes = torch.jit.annotate(List[Tuple[int, int]], [])

        for img in images:
			#对每张图片取得最后两个元素,再pytorch中维度的排列为[channel,height,width]
            val = img.shape[-2:]
            assert len(val) == 2  # 防止输入的是个一维向量
            original_image_sizes.append((val[0], val[1]))
        # original_image_sizes = [img.shape[-2:] for img in images]

		#GeneralizedRCNNTransform 函数 png的第二步(标准化处理、resize大小)
		#现在的image和targets才是真正的batch 我们在输入之前都是一张张尺寸大小不一样的图片,我们这样是没有办法打包成一个batch输入到gpu中进行运算的
        images, targets = self.transform(images, targets)  # 对图像进行预处理

        # print(images.tensors.shape)
        features = self.backbone(images.tensors)  # 将图像输入backbone得到特征图
		#判断特征图是否是tensor类型的,对于上面的图片是img和target型的 但是我们经过backbone后就得到了一个个的特征图(仅有图)
        if isinstance(features, torch.Tensor):  # 若只在一层特征层上预测,将feature放入有序字典中,并编号为‘0’
			#将特征图加入有序字典 key=0 
            features = OrderedDict([('0', features)])  # 若在多层特征层上预测,传入的就是一个有序字典

        # 将特征层以及标注target信息传入rpn中
        # proposals: List[Tensor], Tensor_shape: [num_proposals, 4],是一个绝对坐标
        # 每个proposals是绝对坐标,且为(x1, y1, x2, y2)格式
		#proposal是一个list大小为2(batch_size)是2 每个元素是个tensor,对于每个list而言是个tensor 2000*4 2000代表rpn生成有2000个proposal
        proposals, proposal_losses = self.rpn(images, features, targets)

        # 将rpn生成的数据以及标注target信息传入fast rcnn后半部分
        detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)

        # 对网络的预测结果进行后处理(主要将bboxes还原到原图像尺度上)
        detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)

        losses = {}
        losses.update(detector_losses)
        losses.update(proposal_losses)

        if torch.jit.is_scripting():
            if not self._has_warned:
                warnings.warn("RCNN always returns a (Losses, Detections) tuple in scripting")
                self._has_warned = True
            return losses, detections
        else:
            return self.eager_outputs(losses, detections)

        参数中的image是我们传入的需要预测的图片,是list[Tensor]类型的,注意:这里输入的images的大小都是不同的。后面会进行预处理将这些图片放入同样大小的tensor中打包成一个batch。target就是关于图像的信息。

        其实这两个信息就是上篇博客说的自定义的信息,即自定义数据集中的返回结果,image和target。再通过训练脚本的DataLoader方法传入我们的dataset就会将多张图片以及它们的信息合并在一起返回给我们,也就是这个函数传入的image和target。

         此外,这里的collate.fn方法是代替torch.stack()方法,因为我们不是一个简单的tensor,而是(target,image)的tuple类型。

def collate_fn(batch)
    return tuple(zip(*batch))

        我们看看这个函数的输入是一个list型变量,每个list含八张图片(batch_size),每一个list是一个tuple类型,tuple的第一维是图像image信息,第二维是target信息。

        当我们执行完这个代码后,我们会将每个tuple给拆开,将相同的部分放在一起,即将每一个图像数据image放在一起,将target信息放在一起进行打包。

        现在的data数据是tuple类型的,只有两个元素;每个元素包含八个元素。

 

        现在清晰明了了,这个函数的输入参数image和target是DataLoader返回的信息。

        如果是训练模式,assert targets is not None要保证target不是空的。

        然后检查target["boxes"]是否符合要求,shape第一维度对应的目标有几个,毕竟一个目标就对应一个边界框嘛,第二个维度是4(xminxmax..),如果最后一个维度!=4也要报错。

        声明变量original_image_sizes存储每张图片初始的尺寸

        随后对数据进行预处理:

images, targets = self.transform(images, targets)  # 对图像进行预处理

         经过预处理后得到新的image和targets。因为现在的image和targets才是真正的batch,我们在输入之前都是一张张尺寸大小不一样的图片,我们这样是没有办法打包成一个batch输入到gpu中进行运算的。

       接下来将图像输入backbone得到特征图。

features = self.backbone(images.tensors)

         判断特征图是否是tensor类型的,对于上面的图片是img和target型的,但是我们经过backbone后就得到了一个个的特征图(仅有图)。若只在一层特征层上预测,将feature放入有序字典中,并编号为‘0’。

        将特征层以及标注target信息传入rpn中。

        proposals: List[Tensor], Tensor_shape: [num_proposals, 4],是一个绝对坐标

        每个proposals是绝对坐标,且为(x1, y1, x2, y2)格式

        proposal是一个list大小为2(batch_size)是2 每个元素是个tensor,对于每个list而言是个tensor 2000*4 2000代表rpn生成有2000个proposal

proposals, proposal_losses = self.rpn(images, features, targets)

         将rpn生成的数据以及标注target信息传入fast rcnn后半部分。

detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)

         最后对网络进行后处理(主要将bboxes还原到原图像尺度上)

detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)

         记录损失信息,结束!

2.2 FasterRCNN类 

        在类初始化中,传入了相当多的参数!!

        def __init__(self, backbone,
				#检测的目标类别个数(20+背景)
				num_classes=None,
                 # transform parameter
                 min_size=800, max_size=1333,      # 预处理resize时限制的最小尺寸与最大尺寸
                 image_mean=None, image_std=None,  # 预处理normalize时使用的均值和方差
                 # RPN parameters
                 rpn_anchor_generator=None, rpn_head=None,
                 rpn_pre_nms_top_n_train=2000, rpn_pre_nms_top_n_test=1000,    # rpn中在nms处理前保留的proposal数(根据score)
                 rpn_post_nms_top_n_train=2000, rpn_post_nms_top_n_test=1000,  # rpn中在nms处理后保留的proposal数
                 rpn_nms_thresh=0.7,  # rpn中进行nms处理时使用的iou阈值
                 rpn_fg_iou_thresh=0.7, rpn_bg_iou_thresh=0.3,  # rpn计算损失时,采集正负样本设置的阈值
                 rpn_batch_size_per_image=256, rpn_positive_fraction=0.5,  # rpn计算损失时采样的样本数,以及正样本占总样本的比例
                 rpn_score_thresh=0.0,
                 # Box parameters
                 box_roi_pool=None, box_head=None, box_predictor=None,
                 # 移除低目标概率      fast rcnn中进行nms处理的阈值   对预测结果根据score排序取前100个目标
                 box_score_thresh=0.05, box_nms_thresh=0.5, box_detections_per_img=100,
                 box_fg_iou_thresh=0.5, box_bg_iou_thresh=0.5,   # fast rcnn计算误差时,采集正负样本设置的阈值
                 box_batch_size_per_image=512, box_positive_fraction=0.25,  # fast rcnn计算误差时采样的样本数,以及正样本占所有样本的比例
                 bbox_reg_weights=None):
		#检查backbone是否有out_channels这个属性,对应深度值
        if not hasattr(backbone, "out_channels"):
            raise ValueError(
                "backbone should contain an attribute out_channels"
                "specifying the number of output channels  (assumed to be the"
                "same for all the levels"
            )

		#检查类别
        assert isinstance(rpn_anchor_generator, (AnchorsGenerator, type(None)))
        assert isinstance(box_roi_pool, (MultiScaleRoIAlign, type(None)))

        if num_classes is not None:
            if box_predictor is not None:
                raise ValueError("num_classes should be None when box_predictor "
                                 "is specified")
        else:
            if box_predictor is None:
                raise ValueError("num_classes should not be None when box_predictor "
                                 "is not specified")

        # 预测特征层的channels
        out_channels = backbone.out_channels

        # 若anchor生成器为空,则自动生成针对resnet50_fpn的anchor生成器
		#在五个预测特征层上预测 针对每个预测特征层会使用
        if rpn_anchor_generator is None:
            anchor_sizes = ((32,), (64,), (128,), (256,), (512,))
            aspect_ratios = ((0.5, 1.0, 2.0),) * len(anchor_sizes)
            rpn_anchor_generator = AnchorsGenerator(
                anchor_sizes, aspect_ratios
            )

        # 生成RPN通过滑动窗口预测网络部分
		#
		#
        if rpn_head is None:
            rpn_head = RPNHead(
                out_channels, rpn_anchor_generator.num_anchors_per_location()[0]
            )

        # 默认rpn_pre_nms_top_n_train = 2000, rpn_pre_nms_top_n_test = 1000,
        # 默认rpn_post_nms_top_n_train = 2000, rpn_post_nms_top_n_test = 1000,
        rpn_pre_nms_top_n = dict(training=rpn_pre_nms_top_n_train, testing=rpn_pre_nms_top_n_test)
        rpn_post_nms_top_n = dict(training=rpn_post_nms_top_n_train, testing=rpn_post_nms_top_n_test)

        # 定义整个RPN框架
        rpn = RegionProposalNetwork(
            rpn_anchor_generator, rpn_head,
            rpn_fg_iou_thresh, rpn_bg_iou_thresh,
            rpn_batch_size_per_image, rpn_positive_fraction,
            rpn_pre_nms_top_n, rpn_post_nms_top_n, rpn_nms_thresh,
            score_thresh=rpn_score_thresh)

        #  Multi-scale RoIAlign pooling
		#
		#
        if box_roi_pool is None:
            box_roi_pool = MultiScaleRoIAlign(
                featmap_names=['0', '1', '2', '3'],  # 在哪些特征层进行roi pooling
                output_size=[7, 7],
                sampling_ratio=2)

        # fast RCNN中roi pooling后的展平处理两个全连接层部分
		# out_channels 通过展平之后所拥有的节点个数 由于我们通过proposal通过ROIAlaign之后得到的是一个shape固定的特征矩阵,矩阵的faeatures的通道数=out_channels
		# 特征矩阵的output_size=[7, 7], 因此展平之后的节点个数是out_channels*7*7,第二个参数是全连接层1的节点个数
        if box_head is None:
            resolution = box_roi_pool.output_size[0]  # 默认等于7
            representation_size = 1024
            box_head = TwoMLPHead(
                out_channels * resolution ** 2,
                representation_size
            )

        # 在box_head的输出上预测部分
		#并联两个全连接层 一个全连接层并联(一个全连接层用于预测每个proposal的类别分数)(一个全连接层用于预测每个proposal的边界框回归参数)
        if box_predictor is None:
            representation_size = 1024
            box_predictor = FastRCNNPredictor(
                representation_size,
                num_classes)  #加上背景21

        # 将roi pooling, box_head以及box_predictor结合在一起
        roi_heads = RoIHeads(
            # box
            box_roi_pool, box_head, box_predictor,
            box_fg_iou_thresh, box_bg_iou_thresh,  # 0.5  0.5
            box_batch_size_per_image, box_positive_fraction,  # 512  0.25  在每张图片当中会选取多少个proposal用来计算fastrcnn的损失
            bbox_reg_weights,
            box_score_thresh, box_nms_thresh, box_detections_per_img)  # 0.05  0.5  100

        if image_mean is None:
            image_mean = [0.485, 0.456, 0.406]
        if image_std is None:
            image_std = [0.229, 0.224, 0.225]

        # 对数据进行标准化,缩放,打包成batch等处理部分
        transform = GeneralizedRCNNTransform(min_size, max_size, image_mean, image_std)

        super(FasterRCNN, self).__init__(backbone, rpn, roi_heads, transform)

一、预处理相关参数        

        min_size=800, max_size=1333,      # 预处理resize时限制的最小尺寸与最大尺寸
        image_mean=None, image_std=None,  # 预处理normalize时使用的均值和方差

二、RPN网络参数

        rpn_anchor_generator=None        #anchor生成器

        rpn_head=None          #对应红色方框那块,包括一个3*3的Conv,分类层及框体回归层

        rpn_pre_nms_top_n_train=2000, rpn_pre_nms_top_n_test=1000

        #对应RPN在非极大值抑制保留的proposal数量,是根据预测分数进行保留的,这里NMS有时后相同主要是针对带有FPN的网络。FPN有多个预测特征层,每层在NMS前都保留2000个,总共加起来就上万了。然后在通过NMS保留2000个。
        rpn_post_nms_top_n_train=2000, rpn_post_nms_top_n_test=1000

        #rpn中在nms处理后保留的proposal数。

        rpn_nms_thresh=0.7         # rpn中进行nms处理时使用的iou阈值

        rpn_fg_iou_thresh=0.7, rpn_bg_iou_thresh=0.3,  # rpn计算损失时,采集正负样本设置的阈值。即anchor与groundtruth的iOu大于0.7标记为正样本,anchor与任何一个groundtruth小于0.3标记为负样本

        rpn_batch_size_per_image=256, rpn_positive_fraction=0.5,  # rpn计算损失时采样的样本数,以及正样本占总样本的比例

三、ROIHead的参数

        box_roi_pool=None                               #对应图中的ROI Pooling层

        box_head=None                                    #对应图中Two MLPHead

        box_predictor=None                              #框体预测及类别预测的两个全连接层

        box_score_thresh=0.05                        #PostProcess中滤除小概率目标的阈值

        box_nms_thresh=0.5                             #fast rcnn中进行nms处理的阈值

        box_detections_per_img=100                # 对预测结果根据score排序取前100个目标

        box_fg_iou_thresh=0.5  box_bg_iou_thresh=0.5   

        # fast rcnn计算误差时,采集正负样本设置的阈值

        box_batch_size_per_image=512, box_positive_fraction=0.25,  # fast rcnn计算误差时采样的样本数,以及正样本占所有样本的比例

四、其他初始化部分

        if not hasattr(backbone, "out_channels"):检查backbone是否有out_channels这个属性,对应深度值。在定义模型时,我们会对out_channels设置一个参数。

def create_model(num_classes):
    # https://download.pytorch.org/models/vgg16-397923af.pth
    # 如果使用vgg16的话就下载对应预训练权重并取消下面注释,接着把mobilenetv2模型对应的两行代码注释掉
    # vgg_feature = vgg(model_name="vgg16", weights_path="./backbone/vgg16.pth").features
    # backbone = torch.nn.Sequential(*list(vgg_feature._modules.values())[:-1])  # 删除features中最后一个Maxpool层
    # backbone.out_channels = 512

    # https://download.pytorch.org/models/mobilenet_v2-b0353104.pth
    backbone = MobileNetV2(weights_path="./backbone/mobilenet_v2.pth").features
    backbone.out_channels = 1280  # 设置对应backbone输出特征矩阵的channels

    anchor_generator = AnchorsGenerator(sizes=((32, 64, 128, 256, 512),),
                                        aspect_ratios=((0.5, 1.0, 2.0),))

	#有序字典 我们设置图片的key=0
    roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=['0'],  # 在哪些特征层上进行roi pooling
                                                    output_size=[7, 7],   # roi_pooling输出特征矩阵尺寸
                                                    sampling_ratio=2)  # 采样率

    model = FasterRCNN(backbone=backbone,
                       num_classes=num_classes,
                       rpn_anchor_generator=anchor_generator,
                       box_roi_pool=roi_pooler)

    return model

        #检查类别
        assert isinstance(rpn_anchor_generator, (AnchorsGenerator, type(None)))
        assert isinstance(box_roi_pool, (MultiScaleRoIAlign, type(None)))

        box_roi_pool:featmap_names=['0'],  # 在哪些特征层上进行roi pooling,因为这个网络只有一个预测特征层

                                output_size=[7, 7],   # roi_pooling输出特征矩阵尺寸

        若anchor生成器为空,则自动生成针对resnet50_fpn的anchor生成器。

        对于mobilenet中,由于只有一个预测层,我们负责预测如下尺寸:注意这里的size是元组类型。

anchor_generator = AnchorsGenerator(sizes=((32, 64, 128, 256, 512),),
                                        aspect_ratios=((0.5, 1.0, 2.0),))

        在初始化resnet50+FPN中:每一个值都是一个元组,由于这个网络中有五个预测特征层,针对每个预测特征层不同的尺度分别预测不同的大小,尺寸最大的预测小目标,尺寸最小的特征层预测大目标。

if rpn_anchor_generator is None:
            anchor_sizes = ((32,), (64,), (128,), (256,), (512,))
            aspect_ratios = ((0.5, 1.0, 2.0),) * len(anchor_sizes)
            rpn_anchor_generator = AnchorsGenerator(
                anchor_sizes, aspect_ratios
            )

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven的基本使用方法

Maven Maven是专门用于管理和构建Java项目的工具,它的主要功能有: 提供了一套标准化的项目结构 提供了一套标准化的构建流程(编译,测试,打包,发布……) 提供了一套依赖管理机制 标准化的项…

【JavaEE】Linux

努力经营当下,直至未来明朗! 文章目录一、Linux概述二、 云服务器安装Linux环境 Xshell登录三、Linux中常用指令介绍1. ls2. pwd 查看当前路径对应的绝对路径3. cd 切换当前的工作目录4. touch:创建一个空文件5. cat: 显示文件内…

23 种设计模式总结

title: 23 种设计模式总结 date: 2022-12-30 16:53:46 tags: 设计模式 categories:设计模式 cover: https://cover.png feature: false 文章目录1. 创建型1.1 单例模式(Singleton Design Pattern)1.1.1 概述与实现1.1.2 多例1.2 工厂模式(Fa…

零信任与 K8s 环境实践

零信任的热度自然吸引了大量市场上的关注。尽管如此,零信任并不只是一个空洞的术语:它代表了对未来安全性的一些深刻变革的想法。那么,零信任具体是什么,为什么它会突然变得如此重要?零信任对 Kubernetes 用户来说具体…

【数据结构】顺序表(线性表)的实现

目录 一、什么是顺序表? 二、顺序表的动态实现 1、顺序表初始化 2、顺序表打印 3、顺序表检查空间 4、顺序表尾插 5、顺序表尾删 6、顺序表头插 7、顺序表头删 8、顺序表指定位置插入 9、顺序表指定位置删除 10、顺序表查找 11、顺序表销毁 三、源代码 1、SeqList.h…

hnu社交网络作业1

前言:上的是林剑新老师的课程,还是比较有意思的,此博客用来记录作业的学习情况,答案为老师提供的 一、对于图 1,请回答以下问题,并给出相应的计算过程: (1) 计算图 G 中每个顶点的 closeness 中…

Java重点源码回顾——HashMap1.7

1. 概述 public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, SerializableHashMap在我们的日常使用中非常多&#xff0c;所以今天来阅读下它的源码&#xff0c;了解它具体的设计思想&#xff0c;能够帮助我们扩宽视野。 H…

vmware vcp证书怎么考?vmware vcp证书通过率如何

可为您提供行业领先的虚拟化技术培训和认证服务&#xff0c;这些认证不但会考察您的知识掌握情况和经验水平&#xff0c;还将与您的实际工作职责挂钩。VMware认证按照不同解决方案划分&#xff0c;可分为四条路径&#xff1a;数据中心虚拟化、网络虚拟化、云计算管理和自动化、…

微信小程序项目转uniapp踩坑日记

本文目录一、前言二、转换方式三、后语四、其他&#xff1a;node报错1、包默认C盘存放&#xff0c;而不是安装目录E盘2、正确的环境变量添加3、npm install 命令报错4、npm install -g express报错没有权限一、前言 由于想要把之前完成的微信小程序项目转换成uniapp项目&#…

git入门指南

文章目录Git入门指南前言什么是版本控制系统&#xff08;VCS&#xff09;版本控制系统Git1、概述2、目前比较流行的Git和SVN&#xff0c;区别是什么3、Git安装4、Git的工作区、暂存区、本地仓库、远程仓库5、git的分支6、git的标签7、 实际操作下git常用命令准备操作git cloneg…

Kafka Cluster 扩容 添加副本 重分配分区

Kafka Cluster 扩容 针对kafka集群&#xff0c;可以通过向群集添加新节点来扩展群集。新节点将仅服务于新主题或新分区&#xff0c;现有分区将不会自动重新平衡以使用新节点。如果需要对现有的TOPIC进行重新分配分区&#xff0c;需要运维人员手动进行干预。今天学习下如何对已…

CAPL学习之路-测试功能集函数(故障注入函数)

TestDisableMsg 禁止发送消息,除非调用函数TestSetMsgEvent 使用TestEnableMsg重新启用消息。此函数影响分配CANoe交互层或CANopen仿真的仿真节点 这个函数可以在测试用例中控制Simulation Setup界面仿真节点报文的发送与停止 testcase TCExample() {testDisableMsg(LightSt…

Linux模块代码、编译、加载、卸载一条龙

最近要写一个Linux的内核模块&#xff0c;记录一下内核模块的代码编写、编译、加载和卸载的基本流程&#xff0c;以作备忘&#xff0c;也希望能帮到有需要的同学。 模块代码 //代码来自https://yangkuncn.cn/kernel_INIT_WORK.html //init_works.c #include <linux/kernel…

Docker-compose快速部署PostgreSQL

Docker-compose快速部署PostgreSQL&#xff1a; 利用docker-compose编排工具部署&#xff1a; docker-compose.yml 文件 version: "3.1" services:postgresql:image: postgres:12-alpinecontainer_name: postgresqlenvironment:POSTGRES_DB: postgresPOSTGRES_USE…

Python--数据容器总结

一、数据容器的分类 数据容器可以从一下视角进行简单的分类&#xff1a; 是否支持下标索引 支持&#xff1a;列表、元组、字符串 --序列类型不支持&#xff1a;集合、字典 --非序列类型是否支持重复元素 支持&#xff1a;列表、元组、字符串 --序列类型不支持&#xff1a;集…

自动生成单测代码插件Squaretest

今天来介绍一款工具Squaretest&#xff0c;它是一款自动生成单元测试的插件&#xff0c;会用到它也是因为最近公司上了代码质量管控的指标&#xff0c;会考评各个项目的单元测试覆盖率&#xff0c;以及sonar扫描出来的各种问题。 很多老项目老代码&#xff0c;或者着急交付的项…

第十八讲:神州三层交换机DHCP中继服务的配置

当DHCP客户机和DHCP服务器不在同一个网段时&#xff0c;由DHCP中继传递DHCP报文。增加DHCP中继功能的好处是不必为每个网段都设置DHCP服务器&#xff0c;同一个DHCP服务器可以为很多个子网的客户机提供网络配置参数&#xff0c;即节约了成本又方便了管理。这就是DHCP中继的功能…

vue经历从2.0到3.0更新

​编辑vue专栏收录该内容 9 篇文章2 订阅 订阅专栏 vue经历从2.0到3.0更新之后&#xff0c;简⽽⾔之就是变得更轻&#xff0c;更快&#xff0c;使⽤起来更加⽅便&#xff0c;每⼀次的版本迭代都是对上⼀个版本的升级优化&#xff0c;不管 是对于我们开发者还是对于⽤户体验都…

铁威马NAS教程之使用CloudSync应用轻松同步备份网盘数据

铁威马在TOS 5系统中&#xff0c;将各种云盘的同步集合到了一个应用——CloudSync&#xff0c;更方便用户使用。只需要下载安装CloudSync&#xff0c;就可以在TNAS和各种云盘之间&#xff0c;实现快速安全的数据同步、分享文件。 1.TOS应用中心下载CloudSync应用&#xff1b; …

中国霍尔效应电流传感器市场规模达到了192.71百万美元?

霍尔效应&#xff0c;是指有小电流通过的一个半导体薄片置于磁场中&#xff0c;受到磁场作用影响电流发生偏转&#xff0c;在控制电流的垂直方向上的半导体两侧形成了电压差&#xff0c;该电势差就是霍尔电压。霍尔电压的大小&#xff0c;与磁场强度和半导体内通过的控制电流成…