【多模态融合】TransFusion学习笔记(2)

news2024/9/20 12:41:41

接上篇【多模态融合】TransFusion学习笔记(1)。

从TransFusion-L到TransFusion

    ok,终于可以给出论文中那个完整的框架图了,我第一眼看到这个图有几个疑问:

Q:Image Guidance这条虚线引出的Query Initialization是什么意思?

Q:图像分支中的Image Features as K,V是将整张图像的特征图都作为K,V么?

Q:有了第2阶段之后Initial Prediction还需要么?

Q:如果第一阶段的Q来自纯lidar bev feature map,用它来聚合Image Features靠普么,毕竟是两种模态的特征?

Q:第2阶段的Transformer Decoder Layer with SMCA,这个SMCA是什么意思?

Q:如果仅仅是纯Lidar分支产生的object query去聚合image featuers产生最终的预测肯定是不够的,你可能得到一个修正之后更准的边界框或者分类,但是lidar漏掉的框是没办法恢复的,所以应该还有补漏的环节?

带着诸的疑问结合论文及代码继续分析,仍然假定batch为2,数据集为nuScenes。说到nuScenes需要大该了解以下他lidar和camera配置。他在车顶端配备了一个32线Lidar,然后按321队形配置了6个Camera。所以,代码中推理的时候每一个batch同时包含了6张图像。

 #源文件mmdet3d/models/dense_heads/transfusion_head.py

    def forward(self, feats, img_feats, img_metas):
        """Forward pass.

        Args:
            feats (list[torch.Tensor]): Multi-level features, e.g.,
                features produced by FPN.

        Returns:
            tuple(list[dict]): Output results. first index by level, second index by layer
        """
        if img_feats is None:
            img_feats = [None]
        res = multi_apply(self.forward_single, feats, img_feats, [img_metas])
        assert len(res) == 1, "only support one level features."
        return res

现在再来看Tranfusion检测头推理入口forward函数的时候,img_feats和img_metas就包含了满满的图像及其特征信息了,其中img_feats的shape为(12,256,112,200),12为batch(2)*6(cameras的数量),它将batch和n_views整合在了一起,明白这一点很重要。                                                    

 def forward_single(self, inputs, img_inputs, img_metas):
        """Forward function for CenterPoint.

        Args:
            inputs (torch.Tensor): Input feature map with the shape of
                [B, 512, 128(H), 128(W)]. (consistent with L748)

        Returns:
            list[dict]: Output results for tasks.
        """
        batch_size = inputs.shape[0]
        lidar_feat = self.shared_conv(inputs)  ##=>[2, 128, 128, 128]

        lidar_feat_flatten = lidar_feat.view(batch_size, lidar_feat.shape[1], -1)  #=>[BS, C, H*W]
        bev_pos = self.bev_pos.repeat(batch_size, 1, 1).to(lidar_feat.device)

        if self.fuse_img:
            img_feat = self.shared_conv_img(img_inputs)  # [BS * n_views, C, H, W]
            img_h, img_w, num_channel = img_inputs.shape[-2], img_inputs.shape[-1], img_feat.shape[1]
            # =>[B, C, H, n_views, W]
            raw_img_feat = img_feat.view(batch_size, self.num_views, num_channel, img_h, img_w).permute(0, 2, 3, 1, 4) 
            # =>[B, C, H, n_views*W]
            img_feat = raw_img_feat.reshape(batch_size, num_channel, img_h, img_w * self.num_views)  
            # =>(B,C,n_view*W)
            img_feat_collapsed = img_feat.max(2).values

            # positional encoding for image guided query initialization
            if self.img_feat_collapsed_pos is None:
                img_feat_collapsed_pos = self.img_feat_collapsed_pos 
                                       = self.create_2D_grid(1, img_feat_collapsed.shape[-1]).to(img_feat.device)
            else:
                img_feat_collapsed_pos = self.img_feat_collapsed_pos
            bev_feat = lidar_feat_flatten
            for idx_view in range(self.num_views):
                bev_feat = self.decoder[2 + idx_view](bev_feat, img_feat_collapsed[..., img_w * idx_view:img_w * (idx_view + 1)], 
                    bev_pos, img_feat_collapsed_pos[:, img_w * idx_view:img_w * (idx_view + 1)])

从if self.fuse_img条件判断进入的这段代码逻辑用于生成融合了的LiDAR-Camera BEV feature map F-lc。

图:展示如何操作一个batch中的6张Image feature map,形成高度压缩后的K,V。

图:展示Lidar features和6张Height Collapsed Image features融合的过程

使用Dense的Lidar BEV features作为Q,使用高度压缩后的Image Features作为K,V。为什么要对Image Features进行高度压缩,作者在论文中也做了解释。

关于如何融合lidar bev features和image features得到一个更具表达能力的bev feature map,在若干其它论文中都有涉及,较为著名的比如以下图所示的BEVFusion。

BEVFusion这种特征融合的方式很直观,但是他需要将multi-view的图像特征通过LSS或其它方式编码到BEV空间,然后使用一个Dynamic Fusion Module得到融合后的特征。这种融合简单粗暴,也是Hard-Association的。

考虑一个问题,如果使用BEVFusion这种多模态融合的bev feature map替换TransFusion-L中纯Lidar产生的bev featuremap会有什么效果呢?bevfusion的作者就做了这个实验。

从最后一列的nuScenes Validation上的结果来看mAP和NDS分别提了3.%和1.1%。怎么说呢,有用,但好像又觉得没赚到啥。毕竟费了大力气把不同视角下的image特征提取出来再编码到BEV空间,融合完成后mAP相比纯Lidar只是涨了3个点,基本上还是Lidar在支撑着。

        #################################
        # image guided query initialization
        #################################
        if self.initialize_by_heatmap:
            ##=>[2, 10, 128, 128])
            dense_heatmap = self.heatmap_head(lidar_feat)
            dense_heatmap_img = None
            if self.fuse_img:
                dense_heatmap_img = self.heatmap_head_img(bev_feat.view(lidar_feat.shape))  # [BS, num_classes, H, W]
                heatmap = (dense_heatmap.detach().sigmoid() + dense_heatmap_img.detach().sigmoid()) / 2
            else:
                heatmap = dense_heatmap.detach().sigmoid()
            padding = self.nms_kernel_size // 2
            local_max = torch.zeros_like(heatmap)
            local_max_inner = F.max_pool2d(heatmap, kernel_size=self.nms_kernel_size, stride=1, padding=0)
            local_max[:, :, padding:(-padding), padding:(-padding)] = local_max_inner
            ## for Pedestrian & Traffic_cone in nuScenes
            if self.test_cfg['dataset'] == 'nuScenes':
                local_max[:, 8, ] = F.max_pool2d(heatmap[:, 8], kernel_size=1, stride=1, padding=0)
                local_max[:, 9, ] = F.max_pool2d(heatmap[:, 9], kernel_size=1, stride=1, padding=0)
            elif self.test_cfg['dataset'] == 'Waymo':  # for Pedestrian & Cyclist in Waymo
                local_max[:, 1, ] = F.max_pool2d(heatmap[:, 1], kernel_size=1, stride=1, padding=0)
                local_max[:, 2, ] = F.max_pool2d(heatmap[:, 2], kernel_size=1, stride=1, padding=0)
            ##非max-heat的地方就被set为0了
            heatmap = heatmap * (heatmap == local_max)
            ##torch.Size([2, 10, 16384]) <==
            heatmap = heatmap.view(batch_size, heatmap.shape[1], -1)

            # top #num_proposals among all classes
            top_proposals = heatmap.view(batch_size, -1).argsort(dim=-1, descending=True)[..., :self.num_proposals]
            top_proposals_class = top_proposals // heatmap.shape[-1]

            ##index有什么用??
            top_proposals_index = top_proposals % heatmap.shape[-1]
            query_feat = lidar_feat_flatten.gather(index=top_proposals_index[:, None, :].expand(-1, lidar_feat_flatten.shape[1], -1), dim=-1)
            self.query_labels = top_proposals_class

            one_hot = F.one_hot(top_proposals_class, num_classes=self.num_classes).permute(0, 2, 1)
            query_cat_encoding = self.class_encoding(one_hot.float())
            query_feat += query_cat_encoding

            query_pos = bev_pos.gather(index=top_proposals_index[:, None, :].permute(0, 2, 1).expand(-1, -1, bev_pos.shape[-1]), dim=1)
        else:
            query_feat = self.query_feat.repeat(batch_size, 1, 1)  # [BS, C, num_proposals]
            base_xyz = self.query_pos.repeat(batch_size, 1, 1).to(lidar_feat.device)  # [BS, num_proposals, 2]

回到TransFusion上面,在没有融合Image Features之前,heatmap需要从纯lidar feature map出。现在有了融合后的feature map,自然heatmap又多了一条出路。这就是代码中既有一个dense_heatmap,又多出来了一个dense_heatmap_img,他们最终通过以下代码进行了融合。

heatmap = (dense_heatmap.detach().sigmoid() + dense_heatmap_img.detach().sigmoid()) / 2

不看代码我还以为就只是利用了从dense_heatmap_img出的heatmap,作者这里还是做了一下结合,结合方式也比较简单,各自simgoid之后相加取平均。

        ret_dicts = []
        for i in range(self.num_decoder_layers):
            prefix = 'last_' if (i == self.num_decoder_layers - 1) else f'{i}head_'
            # Transformer Decoder Layer
            # :param query: B C Pq    :param query_pos: B Pq 3/6
            query_feat = self.decoder[i](query_feat, lidar_feat_flatten, query_pos, bev_pos)

            # Prediction
            res_layer = self.prediction_heads[i](query_feat) ##FFN

            res_layer['center'] = res_layer['center'] + query_pos.permute(0, 2, 1)
            first_res_layer = res_layer
            if not self.fuse_img:
                ret_dicts.append(res_layer)

            # for next level positional embedding
            query_pos = res_layer['center'].detach().clone().permute(0, 2, 1)

这段代码和单模态的TransFusion-L比,query_feat还是从纯lidar bev feature map取的,lidar_feat_flatten也还是原来那个展开了的lidar bev featuremap。但是,此时的query_feat所在的热点位置因为是从融合的bev featuremap出的,所以就有了"Image Guidance"的一说。

        #################################
        # transformer decoder layer (img feature as K,V)
        #################################
        if self.fuse_img:
            # positional encoding for image fusion
            img_feat = raw_img_feat.permute(0, 3, 1, 2, 4) # [BS, n_views, C, H, W]
            img_feat_flatten = img_feat.view(batch_size, self.num_views, num_channel, -1)  # [BS, n_views, C, H*W]
            if self.img_feat_pos is None:
                (h, w) = img_inputs.shape[-2], img_inputs.shape[-1]
                img_feat_pos = self.img_feat_pos = self.create_2D_grid(h, w).to(img_feat_flatten.device)
            else:
                img_feat_pos = self.img_feat_pos

            prev_query_feat = query_feat.detach().clone()
            query_feat = torch.zeros_like(query_feat)  # create new container for img query feature

            query_pos_realmetric = query_pos.permute(0, 2, 1) * self.test_cfg['out_size_factor'] * self.test_cfg['voxel_size'][0] + self.test_cfg['pc_range'][0]
            query_pos_3d = torch.cat([query_pos_realmetric, res_layer['height']], dim=1).detach().clone()
            if 'vel' in res_layer:
                vel = copy.deepcopy(res_layer['vel'].detach())
            else:
                vel = None
            pred_boxes = self.bbox_coder.decode(
                copy.deepcopy(res_layer['heatmap'].detach()),
                copy.deepcopy(res_layer['rot'].detach()),
                copy.deepcopy(res_layer['dim'].detach()),
                copy.deepcopy(res_layer['center'].detach()),
                copy.deepcopy(res_layer['height'].detach()),
                vel,
            )
            on_the_image_mask = torch.ones([batch_size, self.num_proposals]).to(query_pos_3d.device) * -1

            for sample_idx in range(batch_size if self.fuse_img else 0):
                lidar2img_rt = query_pos_3d.new_tensor(img_metas[sample_idx]['lidar2img'])
                img_scale_factor = (
                    query_pos_3d.new_tensor(img_metas[sample_idx]['scale_factor'][:2]
                                            if 'scale_factor' in img_metas[sample_idx].keys() else [1.0, 1.0]))
                img_flip = img_metas[sample_idx]['flip'] if 'flip' in img_metas[sample_idx].keys() else False
                img_crop_offset = (
                    query_pos_3d.new_tensor(img_metas[sample_idx]['img_crop_offset'])
                    if 'img_crop_offset' in img_metas[sample_idx].keys() else 0)
                img_shape = img_metas[sample_idx]['img_shape'][:2]
                img_pad_shape = img_metas[sample_idx]['input_shape'][:2]

                boxes = LiDARInstance3DBoxes(pred_boxes[sample_idx]['bboxes'][:, :7], box_dim=7)
                query_pos_3d_with_corners = torch.cat([query_pos_3d[sample_idx], boxes.corners.permute(2, 0, 1).view(3, -1)], dim=-1)  # [3, num_proposals] + [3, num_proposals*8]
                # transform point clouds back to original coordinate system by reverting the data augmentation
                if batch_size == 1:  # skip during inference to save time
                    points = query_pos_3d_with_corners.T
                else:
                    points = apply_3d_transformation(query_pos_3d_with_corners.T, 'LIDAR', img_metas[sample_idx], reverse=True).detach()
                num_points = points.shape[0]

                for view_idx in range(self.num_views):
                    pts_4d = torch.cat([points, points.new_ones(size=(num_points, 1))], dim=-1)
                    pts_2d = pts_4d @ lidar2img_rt[view_idx].t()

                    ##相机内参前面那个1/z
                    pts_2d[:, 2] = torch.clamp(pts_2d[:, 2], min=1e-5)
                    pts_2d[:, 0] /= pts_2d[:, 2]
                    pts_2d[:, 1] /= pts_2d[:, 2]

                    # img transformation: scale -> crop -> flip
                    # the image is resized by img_scale_factor
                    img_coors = pts_2d[:, 0:2] * img_scale_factor  # Nx2
                    img_coors -= img_crop_offset

                    # grid sample, the valid grid range should be in [-1,1]
                    coor_x, coor_y = torch.split(img_coors, 1, dim=1)  # each is Nx1
                    if img_flip:
                        # by default we take it as horizontal flip
                        # use img_shape before padding for flip
                        orig_h, orig_w = img_shape
                        coor_x = orig_w - coor_x

                    ##e.g. 200个proposal总共有200 + 200*8 = 1800个坐标点
                    coor_x, coor_corner_x = coor_x[0:self.num_proposals, :], coor_x[self.num_proposals:, :]
                    coor_y, coor_corner_y = coor_y[0:self.num_proposals, :], coor_y[self.num_proposals:, :]
                    coor_corner_x = coor_corner_x.reshape(self.num_proposals, 8, 1)
                    coor_corner_y = coor_corner_y.reshape(self.num_proposals, 8, 1)
                    coor_corner_xy = torch.cat([coor_corner_x, coor_corner_y], dim=-1)
                    h, w = img_pad_shape
                    on_the_image = (coor_x > 0) * (coor_x < w) * (coor_y > 0) * (coor_y < h)
                    on_the_image = on_the_image.squeeze()
                    # skip the following computation if no object query fall on current image
                    if on_the_image.sum() <= 1:
                        continue
                    on_the_image_mask[sample_idx, on_the_image] = view_idx

                    # add spatial constraint
                    #out_size_factor_img是什么out的factor?
                    center_ys = (coor_y[on_the_image] / self.out_size_factor_img)
                    center_xs = (coor_x[on_the_image] / self.out_size_factor_img)

                    centers = torch.cat([center_xs, center_ys], dim=-1).int()  # center on the feature map
                    corners = (coor_corner_xy[on_the_image].max(1).values - coor_corner_xy[on_the_image].min(1).values) / self.out_size_factor_img
                    
                    #gaosi ge
                    radius = torch.ceil(corners.norm(dim=-1, p=2) / 2).int()  # radius of the minimum circumscribed circle of the wireframe
                    sigma = (radius * 2 + 1) / 6.0
                    """
                    The 2D gaussian weight mask M is generated  in a similar way as Center-Net,
                    Mij = exp(((i-cx)^2+(j-cy)^2)/(sigma*radius^2)),where (i,j) is the spatial indices of the weight mask M,
                    (cx,cy) is the 2D center computed by projecting the query prediction onto the image plane 
                    """
                    distance = (centers[:, None, :] - (img_feat_pos - 0.5)).norm(dim=-1) ** 2
                    gaussian_mask = (-distance / (2 * sigma[:, None] ** 2)).exp()
                    gaussian_mask[gaussian_mask < torch.finfo(torch.float32).eps] = 0  ##太远的地方权重太小,直接给0
                    attn_mask = gaussian_mask

                    query_feat_view = prev_query_feat[sample_idx, :, on_the_image]
                    query_pos_view = torch.cat([center_xs, center_ys], dim=-1)
                    query_feat_view = self.decoder[self.num_decoder_layers](query_feat_view[None], 
                        img_feat_flatten[sample_idx:sample_idx + 1, view_idx], 
                        query_pos_view[None], img_feat_pos, attn_mask=attn_mask.log())
                    query_feat[sample_idx, :, on_the_image] = query_feat_view.clone()
            self.on_the_image_mask = (on_the_image_mask != -1)


            res_layer = self.prediction_heads[self.num_decoder_layers](torch.cat([query_feat, prev_query_feat], dim=1))
            res_layer['center'] = res_layer['center'] + query_pos.permute(0, 2, 1)
            for key, value in res_layer.items():
                pred_dim = value.shape[1]
                res_layer[key][~self.on_the_image_mask.unsqueeze(1).repeat(1, pred_dim, 1)] = first_res_layer[key][~self.on_the_image_mask.unsqueeze(1).repeat(1, pred_dim, 1)]
            ret_dicts.append(res_layer)

上面这段代码是TransFusion的高潮部分,只是现在的为K,V取自Image features。之所以说"取",自然就是每个object query取聚合所有视图下的Image Features,那样效率太低,也难以收敛。问题的关键是一个object query和哪些Image Features建立关联。有了第一阶段预测出的Initial Predict Boxes这个问题就好办一些了。关于怎么利用第一阶段的predict boxes以及Gaussian Circule作者在论文中已经写的很清楚了,应该算是诸多论文中的常规操作。

看到这里其实大该明白了作者所说的"soft-association",虽然由predict boxes到image features借助了标定关系。但是通过object query聚合对应局部image featues这里利用了TransFormer,尤其是利用其中的cross attention做了跟当前object query上下文相关的特征聚合,即使传感器之间没有严格对齐也更加鲁棒。

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

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

相关文章

flex布局与几个实例(含源码)

本文简单的说明下flex布局 有源码实例&#xff0c;后续会持续添加 flex默认主轴是横轴 容器主要有6个属性 flex-direction 决定主轴的方向 flex-direction: row | row-reverse | column | column-reverse; flex-wrap 决定是否换行 flex-wrap: nowrap | wrap | wrap-revers…

JavaAPI---replace

package daysreplace;public class ReplaceTest {public static void main(String[] args) {String str "wwxhhhhhhhhhhh333";System.out.println("替换前的字符串" str);String newstr str.replace("333", "111");System.out.prin…

(第2遍中)内存的堆空间不够 error: MSB3073 超过了 PCH 的虚拟内存范围

压缩包里打开的新工程文件&#xff0c;运行 GenerateProjectFiles.bat 后&#xff0c;再点击 .sln 文件&#xff0c;编译工程&#xff0c;编译了 1.5h 左右&#xff0c;快结束的时候报错如下&#xff1a; 编译器的堆空间不足在第2遍中编译器的堆空间不足error MSB3073: 命令“…

【typescript】面向对象(下篇),包含接口,属性的封装,泛型

假期第八篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 面向对象&#xff1a;程序中所有的操作都需要通过对象来完成 计算机程序的本质就是对现实事物的抽象&#xff0c;抽象的反义词是具体。比如照片是对一个具体的…

大恒IFrameData IImageData转bmp HObject Mat

大恒工业相机采集的帧数据转为其他8bit图像格式 C#转为bmp格式转为Halcon的HObject格式转为OpenCVSharp的Mat格式 回调采集图像的数据类型为IFrameData&#xff0c;单帧采集的数据类型为IImageData&#xff0c;两者的区别为IImageData类多了一个**Destroy()**方法 C# 转为bm…

floyd算法细节

这个不是一篇学习性文章 主要是针对这几天思考的问题进行一些回答 floyD在计网和数据结构和图模型中有广泛的应用算法 很简单但是其中蕴含的原理值得细究。 弗洛伊德算法(Floyd)主要针对多源最短路径,且可以解决路径中有负权的情况(不包含负权回路),但是迪杰斯特拉算法只…

mycat实现mysql读写分离

架构图&#xff1a; 视频地址

逐步解决Could not find artifact com:ojdbc8:jar:12

Could not find artifact com:ojdbc8:jar:12 in central (https://repo.maven.apache.org/maven2) 原因&#xff1a; ojdbc8:jar:12 属于Oracle 数据库链接的一个程序集&#xff0c;缺失的话很有可能会影响数据库链接&#xff0c;蝴蝶效应产生不可预测的BUG&#xff01;但是版…

typescript开发环境搭建

typescript是基于javascript的强类型标记性语言&#xff0c;使用typescript语言可开发出不同规模的、易于扩展的web前端页面应用&#xff0c;本文主要描述typescript的开发环境搭建。 npm install -g typescript 如上所示&#xff0c;在本地开发环境中&#xff0c;使用nodejs…

arduino嵌入式1,LED闪烁案例

CVE系列在等等吧&#xff0c;环境我有点懒得搭建了 文章目录 前言一、anduino是什么玩意儿&#xff1f;二、使用步骤1.找蓝图/画蓝图2.写入数据成果 总结 前言 最近在学习嵌入式开发&#xff0c;我的单片机到了&#xff0c;然后我就沉迷于嵌入式开发的环境中 提示&#xff1a;…

1300*B. Sort the Array(排序构造)

题意&#xff1a; 一个无重复数字的序列&#xff0c;能否反转一个区间使其成为单增序列。 解析&#xff1a; 记录每个点的值和初始下标&#xff0c;然后排序。 对于排好序的序列进行遍历&#xff0c;找出第一段和原序列下标不同的区间并且标记&#xff08;此区间即为翻转的区…

SpringCloud Alibaba - Seata 四种分布式事务解决方案(XA、AT)+ 实践部署(上)

目录 一、Seata 分布式事务解决方案 1.1、XA 模式 1.1.1、XA模式理论 第一阶段&#xff1a; 第二阶段&#xff1a; 1.1.2、Seata 框架中的 XA 模式 第一阶段&#xff1a; 第二阶段&#xff1a; 1.1.3、XA 模式的优缺点 1.2.4、实现Seata 的 XA 模式 a&#xff09;修改…

建筑施工行业招投标资源众包分包系统站点开发

一款针对建筑、施工行业开发的程序系统平台&#xff0c;运营方可以招募企业发布招投标信息以及招聘信息。 核心功能&#xff1a;一、项目招投标众包发布和投标 企业可以根据自身资源或者实际需求发布参与招投标信息&#xff0c;程序后台可以管理、审核用户发布的信息。参与招…

【C++】AVL树 红黑树

AVL树 AVL树也是二叉搜索树的一种。因为对于普通的二叉搜索树&#xff0c;当插入的数据在有序或接近有序的情况下&#xff0c;二叉搜索树很可能退化成单支树&#xff0c;导致查找效率低下。而AVL树就很好的解决了这个问题。 首先&#xff0c;AVL树是一棵二叉搜索树。同时对于A…

appscan的两种手动探索扫描方式

文章目录 一、使用火狐FoxyProxy浏览器代理探索二、使用appscan内置浏览器探索 一、使用火狐FoxyProxy浏览器代理探索 首先火狐浏览器需安装FoxyProxy 先在扩展和主题里搜FoxyProxy 选FoxyProxy Standard,然后添加到浏览器就行 添加后浏览器右上角会有这个插件 打开apps…

JVM篇---第三篇

系列文章目录 文章目录 系列文章目录一、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?二、Java内存结构三、说说对象分配规则一、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文…

Maven 中引用其他项目jar包出现BOOT-INF问题

问题 在B项目中引入A项目的类&#xff0c;但是发现怎么也引入不进来 A项目打包之后&#xff0c;想在B项目中引用jar 在B项目中发现类文件无法引用 参考网上进行清缓存等一系列操作都没有解决。 最后发现引用的jar包中包含BOOT-INF&#xff0c; 然后去A项目中查找&#xff…

云原生边缘计算KubeEdge安装配置

1. K8S集群部署&#xff0c;可以参考如下博客 请安装k8s集群&#xff0c;centos安装k8s集群 请安装k8s集群&#xff0c;ubuntu安装k8s集群 2.安装kubEedge 2.1 编辑kube-proxy使用ipvs代理 kubectl edit configmaps kube-proxy -n kube-system #修改kube-proxy#大约在40多行…

【动手学深度学习-Pytorch版】Transformer代码总结

本文是纯纯的撸代码讲解&#xff0c;没有任何Transformer的基础内容~ 是从0榨干Transformer代码系列&#xff0c;借用的是李沐老师上课时讲解的代码。 本文是根据每个模块的实现过程来进行讲解的。如果您想获取关于Transformer具体的实现细节&#xff08;不含代码&#xff09;可…

多个浮点数精确求和math.fsum()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 多个浮点数精确求和 math.fsum() 选择题 执行结果输出为1.0的函数是? import math a[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1] print("【执行】print(sum(a))") print(sum(a)) p…