Faster RCNN网络源码解读(Ⅵ) --- RPN网络代码解析(上)RPNHead类与AnchorsGenerator类解析

news2024/9/25 17:19:18

目录

一、代码作用(rpn_function.py)

二、代码解析 

2.1 RPNHead类

2.2 AnchorsGenerator类

2.2.1 初始化函数__init__

2.2.2 正向传播过程 forward

2.2.3 set_cell_anchors生成anchors模板 

2.2.4 generate_anchors生成anchors 

2.2.5 cached_grid_anchors 

2.2.6 grid_anchors 


一、代码作用(rpn_function.py)

          如何利用backbone生成的预测特征层来进行目标分数、目标边界框边界的预测以及如何利用AnchorGeneraror生成anchor。

二、代码解析 

2.1 RPNHead类

class RPNHead(nn.Module):
    """
    add a RPN head with classification and regression
    通过滑动窗口计算预测目标概率与bbox regression参数

    Arguments:
        in_channels: number of channels of the input feature
        num_anchors: number of anchors to be predicted
    """

    def __init__(self, in_channels, num_anchors):
        super(RPNHead, self).__init__()

		#定义三个卷积层

        # 3x3 滑动窗口 输入特征矩阵的channel 输出特征矩阵的channel 
        self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1)

        # 计算预测的目标分数(这里的目标只是指前景或者背景)
        self.cls_logits = nn.Conv2d(in_channels, num_anchors, kernel_size=1, stride=1)

        # 计算预测的目标bbox regression参数
        self.bbox_pred = nn.Conv2d(in_channels, num_anchors * 4, kernel_size=1, stride=1)

        for layer in self.children():
            if isinstance(layer, nn.Conv2d):
                torch.nn.init.normal_(layer.weight, std=0.01)
                torch.nn.init.constant_(layer.bias, 0)

	#x是特征矩阵 通过backbone生成的预测特征层
    def forward(self, x):
        # type: (List[Tensor]) -> Tuple[List[Tensor], List[Tensor]]
        logits = []
        bbox_reg = []
        for i, feature in enumerate(x):
            t = F.relu(self.conv(feature))
            logits.append(self.cls_logits(t))
            bbox_reg.append(self.bbox_pred(t))
        return logits, bbox_reg

        在初始化函数中我们定义三个卷积层:

        第一个卷积层conv 的滑动窗口大小是3\times 3的,对应着图中的滑动窗口。

         输入特征矩阵的channels是我们传入的值,我们令输出的特征矩阵的channels = 输入的特征矩阵的channels,步距和padding均为1。

        后面两个卷积层cls_logitsbbox_pred 对应着anchor前景背景分数预测器以及目标回归框的预测器。然后初始化三个卷积层。

        我们看看正向传播过程:

        输入的x就是我们的特征矩阵(经过backbone所生成的预测特征层),我们遍历每个预测特征层enumerate(x),将每个预测特征层通过3\times 3的滑动窗口以及ReLU激活函数得到输出特征矩阵t,将输出特征矩阵分别通过目标分数预测器cls_logits和目标边界框预测器bbox_pred,将结果分别添加到logitsbbox_reg列表中。

2.2 AnchorsGenerator类

2.2.1 初始化函数__init__

	#anchor 的 scale  ... 每个anchor所采用的比例
	#tran_mobile_net
    def __init__(self, sizes=(128, 256, 512), aspect_ratios=(0.5, 1.0, 2.0)):
        super(AnchorsGenerator, self).__init__()

		#判断size的元素是否是list/tuple  在train_res50中调用
        if not isinstance(sizes[0], (list, tuple)):
            # TODO change this
            sizes = tuple((s,) for s in sizes)
        if not isinstance(aspect_ratios[0], (list, tuple)):
            aspect_ratios = (aspect_ratios,) * len(sizes)

        assert len(sizes) == len(aspect_ratios)

        self.sizes = sizes
        self.aspect_ratios = aspect_ratios
        self.cell_anchors = None
        self._cache = {}

        我们传入了两个参数,sizes就是anchor的scale,aspect_ratios是每个anchor所采用的不同的比例。

        我们看看train_mobilenetv2.py脚本中传入的参数:

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

        sizes传入的是一个tuple类型,其中每个元素又是一个tuple类型((32, 64, 128, 256, 512),)aspect_ratios传入的也是一个元组(0.5, 1.0, 2.0),)

        我们首先判断sizes里面的元素是不是list或者tuple类型,不满足。

        我们接着判断aspect_ratios里面的元素是不是list或者tuple类型,不满足。

        判断两元素个数是否相等(都有一个元素),满足。

        对于train_res50_fpn.py脚本来说,没有传入AnchorGenerator这个参数的,在搭建时按默认值进行生成,在faster_rcnn_framework.py脚本中:

        # 若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
            )

        它在搭建时会以默认形式进行生成,anchor_sizes 是tuple类型,tuple的每个元素又是个tuple,每个tuple中只有一个int类型,对应着每个scale,对五个预测特征层进行预测。

        最后我们将这些都赋值给我们的类变量。

2.2.2 正向传播过程 forward

    def forward(self, image_list, feature_maps):
        # type: (ImageList, List[Tensor]) -> List[Tensor]
        # 获取每个预测特征层的尺寸(height, width)
        grid_sizes = list([feature_map.shape[-2:] for feature_map in feature_maps])

        # 获取输入图像的height和width
        image_size = image_list.tensors.shape[-2:]

        # 获取变量类型和设备类型
        dtype, device = feature_maps[0].dtype, feature_maps[0].device

        # one step in feature map equate n pixel stride in origin image
        # 计算特征层上的一步等于原始图像上的步长
		# 图像大小 / 特征矩阵大小
        strides = [[torch.tensor(image_size[0] // g[0], dtype=torch.int64, device=device),
                    torch.tensor(image_size[1] // g[1], dtype=torch.int64, device=device)] for g in grid_sizes]

        # 根据提供的sizes和aspect_ratios生成anchors模板
        self.set_cell_anchors(dtype, device)

		#将anchor模板运用到原图上
        # 计算/读取所有anchors的坐标信息(这里的anchors信息是映射到原图上的所有anchors信息,不是anchors模板)
        # 得到的是一个list列表,对应每张预测特征图映射回原图的anchors坐标信息
        anchors_over_all_feature_maps = self.cached_grid_anchors(grid_sizes, strides)

        anchors = torch.jit.annotate(List[List[torch.Tensor]], [])
        # 遍历一个batch中的每张图像
        for i, (image_height, image_width) in enumerate(image_list.image_sizes):
            anchors_in_image = []
            # 遍历每张预测特征图映射回原图的anchors坐标信息
            for anchors_per_feature_map in anchors_over_all_feature_maps:
                anchors_in_image.append(anchors_per_feature_map)
            anchors.append(anchors_in_image)
        # 将每一张图像的所有预测特征层的anchors坐标信息拼接在一起
        # anchors是个list,每个元素为一张图像的所有anchors信息
        anchors = [torch.cat(anchors_per_image) for anchors_per_image in anchors]
        # Clear the cache in case that memory leaks.
        self._cache.clear()
        return anchors

        我们传入的参数为image_list, feature_mapsimage_list就是一个ImageList的类,我们上篇博客中有说,它存储的是我们在预处理中将图片打包成的一个一个batch(每张图片大小相等)和image_size是每张图片缩放后对应的大小。

Faster RCNN网络源码解读(Ⅴ) --- GeneralizedRCNNTransform图像初始化代码解析https://blog.csdn.net/qq_41694024/article/details/128498697        feature_maps对应着预测特征层的信息,它的类型是List[Tensor]。list元素的个数是预测特征层的个数。

        我们用grid_sizes获取每个预测特征层的尺寸(height, width)。

        我们用image_size 获取图像的大小信息。

        计算特征层上的一步等于原始图像上的步长,方法是遍历grid_sizes(每个预测特征层的长宽),将图像的大小除以特征矩阵的大小得到了一个缩放因子,可以找到原图的每个点对应于特征图的每一个点了。组合成一个list(长,宽)缩放因子存放在stride变量中。

        假如我们得到一个3*3的预测特征层,预测特征层的每个cell在原图上是怎么计算呢? 我们将原图均分成三等份。算出尺寸缩放因子即可找到每个坐标。

        根据提供的sizes和aspect_ratios生成anchors模板。(2.2.3节)。这里模板的高度宽度对应的都是原图上的尺度

        接下来我们要利用我们的anchors模板利用到原图上,通过cached_grid_anchors实现。(2.2.5节),传入的参数为grid_sizes(每个预测特征层的尺寸)和strides(图像大小 / 特征矩阵大小)。

        anchors_over_all_feature_maps 存储的是anchors在原图上的所有坐标信息。

        我们遍历batch中的每张图片。

        # 遍历一个batch中的每张图像
        for i, (image_height, image_width) in enumerate(image_list.image_sizes):
            anchors_in_image = []
            # 遍历每张预测特征图映射回原图的anchors坐标信息
            for anchors_per_feature_map in anchors_over_all_feature_maps:
                anchors_in_image.append(anchors_per_feature_map)
            anchors.append(anchors_in_image)
        # 将每一张图像的所有预测特征层的anchors坐标信息拼接在一起
        # anchors是个list,每个元素为一张图像的所有anchors信息
        anchors = [torch.cat(anchors_per_image) for anchors_per_image in anchors]
        # Clear the cache in case that memory leaks.
        self._cache.clear()
        return anchors

        这里anchors一共有八个元素,因为我们的batch大小是8。每个元素中又是一个list,list元素的个数就是每张图片预测特征层的个数。shape为每个预测特征层上生成的anchors的信息。

         经过cat之后由list换为tensor了。

        返回anchors。

2.2.3 set_cell_anchors生成anchors模板 

    def set_cell_anchors(self, dtype, device):
        # type: (torch.dtype, torch.device) -> None

		#我们类初始化的时候设置为none 第一次调用为空
        if self.cell_anchors is not None:
            cell_anchors = self.cell_anchors
            assert cell_anchors is not None
            # suppose that all anchors have the same device
            # which is a valid assumption in the current state of the codebase
            if cell_anchors[0].device == device:
                return

        # 根据提供的sizes和aspect_ratios生成anchors模板
        # anchors模板都是以(0, 0)为中心的anchor
        cell_anchors = [
			#生成anchor
            self.generate_anchors(sizes, aspect_ratios, dtype, device)
			#size元素的个数 = 预测特征层的个数  ,有几个特征层就会生成多少个anchor模板,将不同层的anchor组合成一个列表
            for sizes, aspect_ratios in zip(self.sizes, self.aspect_ratios)
        ]
		#传给类变量
        self.cell_anchors = cell_anchors

        先判断self.cell_anchors类变量是否为空,因为在初始化的时候我们设置其为空,因此执行下面的代码。

        通过for循环遍历self.sizes, self.aspect_ratios,传入generate_anchors函数中生成anchors。(2.2.4节)

        self.sizes的元素个数就是预测特征层的个数,他有几个预测特征层就会生成几个anchors模板,将不同层的anchors模板组合成一个列表放入cell_anchors变量中。传给类变量self.cell_anchors,其中存放着anchors模板。是[n*4]大小的,以(0,0)为中心,四个坐标是左上角的(x,y)坐标及右下角的(x,y)坐标。

2.2.4 generate_anchors生成anchors 

    def generate_anchors(self, scales, aspect_ratios, dtype=torch.float32, device=torch.device("cpu")):
        # type: (List[int], List[float], torch.dtype, torch.device) -> Tensor
        """
        compute anchor sizes
        Arguments:
            scales: sqrt(anchor_area)
            aspect_ratios: h/w ratios
            dtype: float32
            device: cpu/gpu
        """
        scales = torch.as_tensor(scales, dtype=dtype, device=device)
        aspect_ratios = torch.as_tensor(aspect_ratios, dtype=dtype, device=device)

		#开根号得到每一个anchor的高度、宽度对应的乘法因子
        h_ratios = torch.sqrt(aspect_ratios)
        w_ratios = 1.0 / h_ratios

        # [r1, r2, r3]' * [s1, s2, s3]
        # number of elements is len(ratios)*len(scales)
		#得到每一个anchor的宽度、高度值 战平
        ws = (w_ratios[:, None] * scales[None, :]).view(-1)
        hs = (h_ratios[:, None] * scales[None, :]).view(-1)

        # left-top, right-bottom coordinate relative to anchor center(0, 0)
        # 生成的anchors模板都是以(0, 0)为中心的, shape [len(ratios)*len(scales), 4]
        base_anchors = torch.stack([-ws, -hs, ws, hs], dim=1) / 2

        return base_anchors.round()  # round 四舍五入

        我们得到高度、宽度对应的乘法因子h_ratios 、w_ratios

        计算每个anchors对应的高度和宽度wshs并将其展平处理。

        这里有五个scale和三个ratios,会生成十五个anchors

        ws对应着一个向量,其中有15个元素。对应着15个anchors的宽度。

        最后以(0,0)为中心得到一个anchor的模板,左上角宽度是-宽度/2,y坐标是-高度/2,右下角坐标是高度、宽度除以2。我们再将其在维度为1上进行拼接。

        这里的base_anchor就是15*4的tensor, 15个anchor的左上角的坐标及右下角的坐标。

        如上图的结构。返回给上层调用。

2.2.5 cached_grid_anchors 

    def cached_grid_anchors(self, grid_sizes, strides):
        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]
        """将计算得到的所有anchors信息进行缓存"""
        key = str(grid_sizes) + str(strides)
        # self._cache是字典类型
        if key in self._cache:
            return self._cache[key]
        anchors = self.grid_anchors(grid_sizes, strides)

		#存放安装好的anchors
        self._cache[key] = anchors
        return anchors

        首先我们将我们的grid_sizes和strides转换成字符形式。由于在初始化函数中我们将self._cache类内变量设为空,因此这句代码不执行。

        我们再将grid_sizes, strides传给我们的grid_anchors函数中。(2.2.6节)

        我们得到的anchors是所有预测特征层映射回原图上所生成的anchors信息存储在self._cache[key] 这个字典里。字典的key是str(grid_sizes) + str(strides),返回这个anchors。

2.2.6 grid_anchors 

    # For every combination of (a, (g, s), i) in (self.cell_anchors, zip(grid_sizes, strides), 0:2),
    # output g[i] anchors that are s[i] distance apart in direction i, with the same dimensions as a.
    def grid_anchors(self, grid_sizes, strides):
        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]
        """
        anchors position in grid coordinate axis map into origin image
        计算预测特征图对应原始图像上的所有anchors的坐标
        Args:
            grid_sizes: 预测特征矩阵的height和width
            strides: 预测特征矩阵上一步对应原始图像上的步距
        """
        anchors = []
        cell_anchors = self.cell_anchors
        assert cell_anchors is not None

        # 遍历每个预测特征层的grid_size,strides和cell_anchors
        for size, stride, base_anchors in zip(grid_sizes, strides, cell_anchors):.
			#每一个预测特征层的高度和宽度
            grid_height, grid_width = size
			#每一个预测特征层cell对应原图上的高度和宽度的尺度信息
            stride_height, stride_width = stride
            device = base_anchors.device

            # For output anchor, compute [x_center, y_center, x_center, y_center]
            # shape: [grid_width] 对应原图上的x坐标(列)
            shifts_x = torch.arange(0, grid_width, dtype=torch.float32, device=device) * stride_width
            # shape: [grid_height] 对应原图上的y坐标(行)
            shifts_y = torch.arange(0, grid_height, dtype=torch.float32, device=device) * stride_height

            # 计算预测特征矩阵上每个点对应原图上的坐标(anchors模板的坐标偏移量)
            # torch.meshgrid函数分别传入行坐标和列坐标,生成网格行坐标矩阵和网格列坐标矩阵
            # shape: [grid_height, grid_width]

			#shift_y 25  shift_x 34个元素 代表当前预测特征层的高度和宽度为35*24
            shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)
            shift_x = shift_x.reshape(-1)
            shift_y = shift_y.reshape(-1)

            # 计算anchors坐标(xmin, ymin, xmax, ymax)在原图上的坐标偏移量
            # shape: [grid_width*grid_height, 4]

			#850*4  850是预测特征层的个数 4是
            shifts = torch.stack([shift_x, shift_y, shift_x, shift_y], dim=1)

            # For every (base anchor, output anchor) pair,
            # offset each zero-centered base anchor by the center of the output anchor.

            # 将anchors模板与原图上的坐标偏移量相加得到原图上所有anchors的坐标信息(shape不同时会使用广播机制) 850*15*4
			#一共有850个cell 每个cell生成15个anchor 
            shifts_anchor = shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)
            anchors.append(shifts_anchor.reshape(-1, 4))

		#12750*4
        return anchors  # List[Tensor(all_num_anchors, 4)]

        grid_sizes存放着每个预测特征层的尺寸(高宽)。

        strides存放图像大小 / 预测特征层矩阵大小。

        我们将之前计算出的anchors模板赋值给cell_anchors变量。

        遍历每个预测特征层的grid_sizestridescell_anchors

        每一个预测特征层的高度和宽度放入变量grid_height, grid_width中。

        每一个预测特征层cell对应原图上的高度和宽度的尺度信息stride_height, stride_width

        通过torch.arange方法生成一个(0, grid_width)的序列,再将其乘stride_width。

         这里就好比我们在长度和宽度上生成一个序列,以右图宽度为例。假设这个cell的宽度为3,它生成的序列就是[0,1,2],我们知道每个cell对应原图的尺寸 stride_width,我们将[0,1,2]乘以这个尺度就能得到这个原图对应cell的x轴坐标。分别就是这三个点对应的x轴坐标。同理可以得到原图的y轴坐标。

        于是shifts_xshifts_y变量存储着cell的点对应原图上的坐标。

        我们再通过torch.meshgrid方法将我们得到的shifts_xshifts_y得到预测特征层每个点对应原图的一个坐标

         shifts_y是一个拥有25个元素的一个向量。

        shifts_x是一个拥有34个元素的一个向量。

        说明我们的预测特征层的高度和宽度分别对应25和34。

        我们最终得到的shifts_x是一个25\times34的向量,对应预测特征层对应的每一个x坐标。

         shifts = torch.stack([shift_x, shift_y, shift_x, shift_y], dim=1),在维度1上进行拼接,我们设置断点看看shifts的格式。

        是一个[850*4]的向量,对应着预测特征层上的cell个数,4就是左上角坐标和右下角坐标。

        我们之前得到了anchors模板,它是以(0,0)为中心的,我们也得到了特征矩阵的每个cell映射回原图的坐标信息,我们将anchors模板分别叠加在每个cell坐标上。

        shifts_anchor = shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)

        这就是这行代码的作用。

        shifts_anchor的shape我们调试如下:

        这里的850对应着feature一共有850个cell(25\times34),每个cell会生成15个anchor,每个anchor有四个坐标。

        进行reshape处理,最后返回一个列表,列表的元素个数为预测特征层的个数,我们拿mobilenet为例其只有一个预测特征层因此其size为1。

        其shape:

        其每个元素为每个预测特征层的每个cell映射会原图上生成的所有的anchors的坐标信息。返回这个信息。

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

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

相关文章

【Linux】vim 中批量添加注释

本期主题:vim 中批量添加注释博客主页:小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限,出现错误希望大家不吝赐 此文主要介绍两种方法:方法一 :块选择模式;方法二: 替换命令 &#x…

Java基础随手记

数组 数组的使用 数组可以存放多个同一类型的数据,数组也是一种数据类型,是引用类型。即:数组就是一组数据 问题引入 传统的解决方式 使用数组来解决 可以看到,我们创建了一个double类型元素的数组,将我们要计算…

buuctf-misc-[GKCTF 2021]你知道apng吗1

先下载附件,快要过年了,十二月份还没发过文章,紧急写一篇。 下载文件后缀名为apng 搜索一下APNG(基于PNG的位图动画格式)_百度百科 利用火狐浏览器可以打开 类似gif图片的格式,用专门工具进行拆解&#xf…

MySQL内部的核心组件

mysql前言 1.MySQL的驱动 2.数据库的连接池 3.MySQL的工作线程 4.SQL接口 5.SQL解析器 6.查询优化器 7.执行器组件 8.存储引擎接口 1.MySQL的驱动是做什么的? 尤其记得刚刚学习MySQL的时候,引入的pom坐标:mysql-connector-java,这…

软考- 计算机组成原理与体系结构

【考点梳理】 考点1、数据的表示(★★★★) 考点1.1、进制的转换 【考法分析】 本考点的基本考法是与内存地址计算、IP地址计算结合考查。 【要点分析】 1、十进制转R进制(短除法); 2、R进制转十进制&#xff0…

Arduino与Proteus仿真实例-WS2812实现音乐氛围灯仿真

WS2812实现音乐氛围灯仿真 本文将使用WS2812实现一个音乐氛围灯。Arduino通过检测音频信号强度,然后转换成W2812灯带驱动信号,从而实现音乐氛围灯。 WS2812的驱动和使用在前面的文章中作了详细的介绍,请参考: Arduino与Proteus仿真实例-WS2812-RGB-LED灯带酷炫效果仿真Ar…

【软件质量】软件质量分析总结报告

软件质量-----“软件与明确地和隐含地定义的需求相一致的程度” 一、质量的概念 Ⅰ、传统的质量概念:产品性能是否符合技术规范 Ⅱ、质量是一组固有特性满足要求的程度 Ⅲ、适用性质量 Ⅳ、质量不仅指产品质量,也指过程和体系的质量 二、软件质量 Ⅰ、产品质…

教你如何用一行Python代码实现GUI图形界面

文章目录一、选择文件夹二、选择文件三、选择日期四、输入文本五、弹窗无按钮六、弹窗无标题七、弹窗只有OK按钮八、弹窗只有Error按钮(红色)九、显示通知窗口十、弹窗选择十一、自定义弹窗实战一、选择文件夹 首先导入PySimpleGUI库,并且用缩写sg来表示。 import…

Kubernetes 笔记(02)— 基本架构、工作机制简述、Master 组件、Node 组件

1. Kubernetes 的基本架构 Kubernetes 采用了现今流行的“控制面 / 数据面”(Control Plane / Data Plane)架构,集群里的计算机被称为“节点”(Node),可以是实机也可以是虚机,少量的节点用作控制…

【CUDA入门笔记】GPU存储结构模型(2)

GPU存储结构模型 1.CPU可以读写GPU设备中的Global Memory、Constant Memory以及Texture Memory内存储的内容;主机代码可以把数据传输到设备上,也可以从设备中读取数据; 2.GPU中的线程使用Register、Shared Memory、Local Memory、Global Me…

python网络程序设计,TCP协议客户端服务端智能聊天设计

计算机网络基础知识 网络体系结构,分层设计的好处 网络协议三要素:语法、语义、时序 常见应用层协议:ftp、http、smtp、pop3、telnet…… 传输层主要概念:TCP、UDP、端口号 IP地址 MAC地址 计算机网络基础知识 IP地址 1.IP地址 …

内核RCU的一次实践——实战中加深了理解

遍历内核链表是个常规操作,遍历链表过程可能会向链表增加新成员或者从链表剔除老成员,因此遍历链表时一般需要spin lock加锁保护。如果向链表增加新成员或者从链表剔除老成员不经常出现,大部分只是遍历查询链表中成员,此时链表遍…

Spring Cloud:eureka注册中心

在传统的单体应用中,所有的业务都集中在一个服务器中,当浏览器发起请求时,通过前端请求调用后端接口,后端接口调用相应的业务并在前端进行响应,整个的调用就是从请求到响应的一条龙服务。所以不存在服务之间的中转&…

jetson nano GPIO引脚控制舵机

文章目录一.舵机介绍二.舵机工作原理180度舵机360度舵机三.利用jetson nano GPIO控制舵机1.jetson nano与舵机接2.c编写程序输出脉冲(Qt做界面)一.舵机介绍 舵机,是指在自动驾驶仪中操纵飞机舵面(操纵面)转动的一种执行部件。分有&#xff1a…

代码随想录算法训练营第十三天(栈与队列)| 239. 滑动窗口最大值,347.前 K 个高频元素

代码随想录算法训练营第十三天(栈与队列)| 239. 滑动窗口最大值,347.前 K 个高频元素 239. 滑动窗口最大值 之前讲的都是栈的应用,这次该是队列的应用了。 本题算比较有难度的,需要自己去构造单调队列,建…

std::map使用方式以及注意事项(关于相同key的问题)

std::map的使用在C开发中也是经常会用到的一些东西,这里进行一些简单的使用记录,包括如何插入、删除以及修改等。 1、std::map插入: map的插入使用的是insert的方式,一个map包含了key与value两个值。首先需要对两个值进行赋值&a…

Spring Security认证授权练手小项目 腾讯视频VIP权限管理功能

腾讯视频VIP权限管理1、项目功能视频演示2、需求与设计1、需求2、功能概要3、接口设计3、项目源码结构4、项目源码下载5、项目部署1、部署架构2、数据库环境准备3、redis环境准备4、Spring Boot服务准备5、nginx负载均衡准备6、nginx静态资源服务器准备6、项目介绍1、技术架构2…

人工智能-集成学习

1、 集成学习算法介绍 1.1 什么是集成学习 集成学习通过建立几个模型来解决单一预测问题。工作原理:生成多个分类器/模型,各自独立地学习和做出预测。这些预测再结合成组合预测,因此由于任何一个单分类的预测。 1.2 机器学习的两个核心任…

优化RPC网络通信

文章目录什么是RPC通信RPCRPC框架SOARPC通信得重要性具体优化措施1.扩展其他RPC框架.2.选择合适的通信协议3.使用单一长连接4.优化Socket通信.5.高性能的序列化协议6.量身定做报文格式什么是RPC通信 RPC RPC(Remote Process Call),即远程服…

算法训练 —— 链表(2)

目录 1. LeetCode24. 两两交换链表中的结点 2. LeetCode19. 删除链表的倒数第N个节点 3. LeetCode160.相交链表 4. LeetCode141.环形链表 5. LeetCode142.环形链表II 6. LeetCode138.复制带随机指针的链表 1. LeetCode24. 两两交换链表中的结点 两两交换链表中的结点 …