基于LoFTR_TRT项目实现LoFTR模型的trt推理与onnx推理,3060显卡下320图像30ms一组图

news2024/11/26 4:36:54

本博文主要记录了使用LoFTR_TRT项目将LoFTR模型导出为onnx模型,然后将onnx模型转化为trt模型。并分析了LoFTR_TRT与LoFTR的基本代码差异,但从最后图片效果来看是与官网demo基本一致的,具体可以查看上一篇博客记录。最后记录了onnx模型的使用【特征点提取、图像重叠区提取】,同时记录了在3060显卡,cuda12.1+ort17.1,输入尺寸为320x320的环境下,30ms一组图。

项目地址:https://github.com/Kolkir/LoFTR_TRT
模型地址:https://drive.google.com/drive/folders/1DOcOPZb3-5cWxLqn256AhwUVjBPifhuf

1、基本环境准备

这里要求已经安装好torch-gpu、onnxruntime-gpu环境。

1.1 下载安装tensorRT推理库

1、根据cuda版本下载最新的tensorrt,解压后,设置好环境变量即可

tensorrt下载地址:https://developer.nvidia.com/nvidia-tensorrt-8x-download

配置环境变量细节如下所示:
在这里插入图片描述

2、然后查看自己的python版本
在这里插入图片描述
3、安装与版本对应的tensorRT库

在这里插入图片描述

1.2 下载LoFTR_TRT项目与模型

下载https://github.com/Kolkir/LoFTR_TRT项目
在这里插入图片描述
下载预训练模型,https://drive.google.com/drive/folders/1DOcOPZb3-5cWxLqn256AhwUVjBPifhuf
在这里插入图片描述
将下载好的模型解压,放到项目根目录下,具体组织形式如下所示。
在这里插入图片描述

2、代码改动分析

正常LoFTR模型是无法导出为onnx模型的,为此对LoFTR_TRT-main项目代码进行分析。通过其官网说明einsum and einops were removed,可以发现其移除了einsum 与einops 操作

2.1 主流程

通过LoFTR_TRT-main中loftr\loftr.py,可以看到与原始的loftr模型forward不一样。原始loftr模型有下面的三个步骤

        self.fine_preprocess = FinePreprocess(config)
        self.loftr_fine = LocalFeatureTransformer(config["fine"])
        self.fine_matching = FineMatching()

而改动后的loftr,滤除了这三个步骤。同时对于 rearrange操作,使用了torch进行改写。此外,对于图像特征结果feat_c0, feat_f0, feat_c1, feat_f1,只使用了feat_c0与feat_c1。同时模型输出的只是原始LoFTR的中间数据 conf_matrix,需要特定后处理。

import torch
import torch.nn as nn

from .backbone import build_backbone
from .utils.position_encoding import PositionEncodingSine
from .loftr_module import LocalFeatureTransformer
from .utils.coarse_matching import CoarseMatching


class LoFTR(nn.Module):
    def __init__(self, config):
        super().__init__()
        # Misc
        self.config = config

        # Modules
        self.backbone = build_backbone(config)
        self.pos_encoding = PositionEncodingSine(
            config['coarse']['d_model'],
            temp_bug_fix=config['coarse']['temp_bug_fix'])
        self.loftr_coarse = LocalFeatureTransformer(config['coarse'])
        self.coarse_matching = CoarseMatching(config['match_coarse'])
        self.data = dict()

    def backbone_forward(self, img0, img1):
        """
            'img0': (torch.Tensor): (N, 1, H, W)
            'img1': (torch.Tensor): (N, 1, H, W)
        """

        # we assume that data['hw0_i'] == data['hw1_i'] - faster & better BN convergence
        feats_c, feats_i, feats_f = self.backbone(torch.cat([img0, img1], dim=0))

        feats_c, feats_f = self.backbone.complete_result(feats_c, feats_i, feats_f)
        bs = 1
        (feat_c0, feat_c1), (feat_f0, feat_f1) = feats_c.split(bs), feats_f.split(bs)

        return feat_c0, feat_f0, feat_c1, feat_f1

    def forward(self, img0, img1):
        """ 
            'img0': (torch.Tensor): (N, 1, H, W)
            'img1': (torch.Tensor): (N, 1, H, W)
        """
        # 1. Local Feature CNN
        feat_c0, feat_f0, feat_c1, feat_f1 = self.backbone_forward(img0, img1)

        # 2. coarse-level loftr module
        # add featmap with positional encoding, then flatten it to sequence [N, HW, C]
        # feat_c0 = rearrange(self.pos_encoding(feat_c0), 'n c h w -> n (h w) c')
        # feat_c1 = rearrange(self.pos_encoding(feat_c1), 'n c h w -> n (h w) c')
        feat_c0 = torch.flatten(self.pos_encoding(feat_c0), 2, 3).permute(0, 2, 1)
        feat_c1 = torch.flatten(self.pos_encoding(feat_c1), 2, 3).permute(0, 2, 1)

        feat_c0, feat_c1 = self.loftr_coarse(feat_c0, feat_c1)

        # 3. match coarse-level
        conf_matrix = self.coarse_matching(feat_c0, feat_c1)

        return conf_matrix

    def load_state_dict(self, state_dict, *args, **kwargs):
        for k in list(state_dict.keys()):
            if k.startswith('matcher.'):
                state_dict[k.replace('matcher.', '', 1)] = state_dict.pop(k)
        return super().load_state_dict(state_dict, *args, **kwargs)

2.2 后处理

通过对LoFTR_TRT项目中webcam.py分析,发现其输出结果依赖get_coarse_match函数,才可抽取出mkpts0, mkpts1, mconf 信息。
使用代码如下:

mkpts0, mkpts1, mconf = get_coarse_match(conf_matrix, img_size[1], img_size[0], loftr_coarse_resolution)

get_coarse_match函数的定义实现如下,有一个重要参数resolution,其值默认为16。如果需要实现c++部署,则需要将以下代码修改为c++,可以参考numcpp进行改写实现

def get_coarse_match(conf_matrix, input_height, input_width, resolution):
    """
        Predicts coarse matches from conf_matrix
    Args:
        resolution: image
        input_width:
        input_height:
        conf_matrix: [N, L, S]

    Returns:
        mkpts0_c: [M, 2]
        mkpts1_c: [M, 2]
        mconf: [M]
    """

    hw0_i = (input_height, input_width)
    hw0_c = (input_height // resolution, input_width // resolution)
    hw1_c = hw0_c  # input images have the same resolution
    feature_num = hw0_c[0] * hw0_c[1]

    # 3. find all valid coarse matches
    # this only works when at most one `True` in each row
    mask = conf_matrix
    all_j_ids = mask.argmax(axis=2)
    j_ids = all_j_ids.squeeze(0)
    b_ids = np.zeros_like(j_ids, dtype=np.long)
    i_ids = np.arange(feature_num, dtype=np.long)

    mconf = conf_matrix[b_ids, i_ids, j_ids]

    # 4. Update with matches in original image resolution
    scale = hw0_i[0] / hw0_c[0]
    mkpts0_c = np.stack(
        [i_ids % hw0_c[1], np.trunc(i_ids / hw0_c[1])],
        axis=1) * scale
    mkpts1_c = np.stack(
        [j_ids % hw1_c[1], np.trunc(j_ids / hw1_c[1])],
        axis=1) * scale

    return mkpts0_c, mkpts1_c, mconf

3、模型导出

安装依赖项目:
pip install yacs
pip install pycuda #trt运行必须,ort运行可以忽略

3.1 导出配置说明

loftr\utils\cvpr_ds_config.py对应着导出模型的参数设置,主要是针对图像的宽高、BORDER_RM 、DSMAX_TEMPERATURE 等参数

from yacs.config import CfgNode as CN


def lower_config(yacs_cfg):
    if not isinstance(yacs_cfg, CN):
        return yacs_cfg
    return {k.lower(): lower_config(v) for k, v in yacs_cfg.items()}


_CN = CN()
_CN.BACKBONE_TYPE = 'ResNetFPN'
_CN.RESOLUTION = (8, 2)  # options: [(8, 2)]
_CN.INPUT_WIDTH = 640
_CN.INPUT_HEIGHT = 480

# 1. LoFTR-backbone (local feature CNN) config
_CN.RESNETFPN = CN()
_CN.RESNETFPN.INITIAL_DIM = 128
_CN.RESNETFPN.BLOCK_DIMS = [128, 196, 256]  # s1, s2, s3

# 2. LoFTR-coarse module config
_CN.COARSE = CN()
_CN.COARSE.D_MODEL = 256
_CN.COARSE.D_FFN = 256
_CN.COARSE.NHEAD = 8
_CN.COARSE.LAYER_NAMES = ['self', 'cross'] * 4
_CN.COARSE.TEMP_BUG_FIX = False

# 3. Coarse-Matching config
_CN.MATCH_COARSE = CN()

_CN.MATCH_COARSE.BORDER_RM = 2
_CN.MATCH_COARSE.DSMAX_TEMPERATURE = 0.1

default_cfg = lower_config(_CN)

3.2 导出onnx模型

运行export_onnx.py即可导出模型,修改weights参数可以选择要导出的预训练权重,配置prune参数的efault=True,可以导出剪枝后的模型

import argparse
from loftr import LoFTR, default_cfg
import torch
import torch.nn.utils.prune as prune


def main():
    parser = argparse.ArgumentParser(description='LoFTR demo.')
    parser.add_argument('--weights', type=str, default='weights/outdoor_ds.ckpt',
                        help='Path to network weights.')
    parser.add_argument('--device', type=str, default='cuda',
                        help='cpu or cuda')
    parser.add_argument('--prune', default=False, help='Do unstructured pruning')

    opt = parser.parse_args()
    print(opt)

    device = torch.device(opt.device)

    print('Loading pre-trained network...')
    model = LoFTR(config=default_cfg)
    checkpoint = torch.load(opt.weights)
    if checkpoint is not None:
        missed_keys, unexpected_keys = model.load_state_dict(checkpoint['state_dict'], strict=False)
        if len(missed_keys) > 0:
            print('Checkpoint is broken')
            return 1
        print('Successfully loaded pre-trained weights.')
    else:
        print('Failed to load checkpoint')
        return 1

    if opt.prune:
        print('Model pruning')
        for name, module in model.named_modules():
            # prune connections in all 2D-conv layers
            if isinstance(module, torch.nn.Conv2d):
                prune.l1_unstructured(module, name='weight', amount=0.5)
                prune.remove(module, 'weight')
            # prune connections in all linear layers
            elif isinstance(module, torch.nn.Linear):
                prune.l1_unstructured(module, name='weight', amount=0.5)
                prune.remove(module, 'weight')
        weight_total_sum = 0
        weight_total_num = 0
        for name, module in model.named_modules():
            # prune connections in all 2D-conv layers
            if isinstance(module, torch.nn.Conv2d):
                weight_total_sum += torch.sum(module.weight == 0)
            # prune connections in all linear layers
            elif isinstance(module, torch.nn.Linear):
                weight_total_num += module.weight.nelement()

        print(f'Global sparsity: {100. * weight_total_sum / weight_total_num:.2f}')

    print(f'Moving model to device: {device}')
    model = model.eval().to(device=device)

    with torch.no_grad():
        dummy_image = torch.randn(1, 1, default_cfg['input_height'], default_cfg['input_width'], device=device)
        torch.onnx.export(model, (dummy_image, dummy_image), 'loftr.onnx', verbose=True, opset_version=11)


if __name__ == "__main__":
    main()

代码运行成功后,会在根目录下,生成 loftr.onnx
在这里插入图片描述

3.3 onnx模型转trt模型

先将前面转换好的onnx模型上传到https://netron.app/进行分析,可以发现是一个静态模型。
在这里插入图片描述
转换命令:trtexec --onnx=loftr.onnx --workspace=4096 --saveEngine=loftr.trt --fp16
具体执行效果如下所示,生成了 loftr.trt
在这里插入图片描述

4、运行模型

4.1 前置修改

修改一: utils.py 中np.long修改为np.int64,具体操作为将代码中第30行与31行修改为以下

    b_ids = np.zeros_like(j_ids, dtype=np.int64)
    i_ids = np.arange(feature_num, dtype=np.int64)

如果电脑没有摄像头,则需要进行下列额外代码修改

修改一: webcam.py中默认参数camid,类型修改为str,默认值修改为自己准备好的视频文件

def main():
    parser = argparse.ArgumentParser(description='LoFTR demo.')
    parser.add_argument('--weights', type=str, default='weights/outdoor_ds.ckpt',
                        help='Path to network weights.')
    # parser.add_argument('--camid', type=int, default=0,
    #                     help='OpenCV webcam video capture ID, usually 0 or 1.')
    parser.add_argument('--camid', type=str, default=r"C:\Users\Administrator\Videos\风景视频素材分享_202477135455.mp4",
                        help='OpenCV webcam video capture ID, usually 0 or 1.')

修改二:camera.py中init函数修改为以下,用于支持读取视频文件

class Camera(object):
    def __init__(self, index):
        if isinstance(index,int):#加载摄像头视频流
            self.cap = cv2.VideoCapture(index, cv2.CAP_V4L2)
        else:#加载视频
            self.cap = cv2.VideoCapture(index)
        if not self.cap.isOpened():
            print('Failed to open camera {0}'.format(index))
            exit(-1)

        # self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
        # self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)

        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()
        self.status = False
        self.frame = None

将推理时的图像分辨率修改为320x240 ,即将webcam.py中的 img_size 设置(320, 240),loftr\utils\cvpr_ds_config.py中对应的设置

_CN.INPUT_WIDTH = 320
_CN.INPUT_HEIGHT = 240

然后运行webcam.py,可以发现fps为20左右,此时硬件环境为3060显卡。与https://hpg123.blog.csdn.net/article/details/140235431中的分析一致,40ms左右处理完一张图片。
在这里插入图片描述
在这里插入图片描述

4.2 torch模型运行

直接运行 webcam.py ,可以看到fps为5
在这里插入图片描述

4.3 trt模型运行

修改webcam.py 中的trt配置,为其添加默认值 loftr.trt,具体修改如以下代码的最后一行。

def main():
    parser = argparse.ArgumentParser(description='LoFTR demo.')
    parser.add_argument('--weights', type=str, default='weights/outdoor_ds.ckpt',
                        help='Path to network weights.')
    # parser.add_argument('--camid', type=int, default=0,
    #                     help='OpenCV webcam video capture ID, usually 0 or 1.')
    parser.add_argument('--camid', type=str, default=r"C:\Users\Administrator\Videos\风景视频素材分享_202477135455.mp4",
                        help='OpenCV webcam video capture ID, usually 0 or 1.')
    parser.add_argument('--device', type=str, default='cuda',
                        help='cpu or cuda')
    parser.add_argument('--trt', type=str, default='loftr.trt', help='TensorRT model engine path')

运行效果如下,发现fps是2,比较低,不如torch运行
在这里插入图片描述

5、onnx模型推理

章节4中是原作者实现的推理代码,这里参考https://hpg123.blog.csdn.net/article/details/137381647中的代码进行推理实现。

5.1 依赖库与前置操作

操作一:
将 博客 https://hpg123.blog.csdn.net/article/details/124824892 中的代码保存为 imgutils.py
操作二:
将 cvpr_ds_config.py中的宽高配置,修改为320x320,然后重新运行export_onnx.py,导出onnx模型

_CN.INPUT_WIDTH = 320
_CN.INPUT_HEIGHT = 320

运行后生成的模型结构如下所示
在这里插入图片描述

5.2 运行代码

将下列代码保存为onnx_infer.py ,代码中有几行是计算运行时间的,可以删除。

from imgutils import *
import onnxruntime as ort
import numpy as np
import time
def get_coarse_match(conf_matrix, input_height, input_width, resolution):
    """
        Predicts coarse matches from conf_matrix
    Args:
        resolution: image
        input_width:
        input_height:
        conf_matrix: [N, L, S]

    Returns:
        mkpts0_c: [M, 2]
        mkpts1_c: [M, 2]
        mconf: [M]
    """

    hw0_i = (input_height, input_width)
    hw0_c = (input_height // resolution, input_width // resolution)
    hw1_c = hw0_c  # input images have the same resolution
    feature_num = hw0_c[0] * hw0_c[1]

    # 3. find all valid coarse matches
    # this only works when at most one `True` in each row
    mask = conf_matrix
    all_j_ids = mask.argmax(axis=2)
    j_ids = all_j_ids.squeeze(0)
    b_ids = np.zeros_like(j_ids, dtype=np.int64)
    i_ids = np.arange(feature_num, dtype=np.int64)

    mconf = conf_matrix[b_ids, i_ids, j_ids]

    # 4. Update with matches in original image resolution
    scale = hw0_i[0] / hw0_c[0]
    mkpts0_c = np.stack(
        [i_ids % hw0_c[1], np.trunc(i_ids / hw0_c[1])],
        axis=1) * scale
    mkpts1_c = np.stack(
        [j_ids % hw1_c[1], np.trunc(j_ids / hw1_c[1])],
        axis=1) * scale

    return mkpts0_c, mkpts1_c, mconf

model_name="loftr.onnx"
model = ort.InferenceSession(model_name,providers=['CUDAExecutionProvider'])

img_size=(320,320)
loftr_coarse_resolution=8
tensor2a,img2a=read_img_as_tensor_gray(r"C:\Users\Administrator\Pictures\t1.jpg",img_size,device='cpu')
tensor2b,img2b=read_img_as_tensor_gray(r"C:\Users\Administrator\Pictures\t2.jpg",img_size,device='cpu')
data={'img0':tensor2a.numpy(),'img1':tensor2b.numpy()}
conf_matrix = model.run(None,data)[0]
mkpts0, mkpts1, confidence = get_coarse_match(conf_matrix, img_size[1], img_size[0], loftr_coarse_resolution)
#-----------计算运行时间---------------------
times=10
st=time.time()
for i in range(times):
    conf_matrix = model.run(None,data)[0]
    mkpts0, mkpts1, confidence = get_coarse_match(conf_matrix, img_size[1], img_size[0], loftr_coarse_resolution)
et=time.time()
runtime=(et-st)/times
print(f"{img_size} 图像推理时间为: {runtime:.4f}")

#myimshows( [img2a,img2b],size=12)

import cv2 as cv
pt_num = mkpts0.shape[0]
im_dst,im_res=img2a,img2b
img = np.zeros((max(im_dst.shape[0], im_res.shape[0]), im_dst.shape[1]+im_res.shape[1]+10,3))
img[:,:im_res.shape[0],]=im_dst
img[:,-im_res.shape[0]:]=im_res
img=img.astype(np.uint8)
match_threshold=0.6
for i in range(0, pt_num):
    if (confidence[i] > match_threshold):
        pt0 = mkpts0[i].astype(np.int32)
        pt1 = mkpts1[i].astype(np.int32)
        #cv.circle(img, (pt0[0], pt0[1]), 1, (0, 0, 255), 2)
        #cv.circle(img, (pt1[0], pt1[1]+650), (0, 0, 255), 2)
        cv.line(img, pt0, (pt1[0]+im_res.shape[0], pt1[1]), (0, 255, 0), 1)
myimshow( img,size=12)

import cv2
def getGoodMatchPoint(mkpts0, mkpts1, confidence,  match_threshold:float=0.5):
    print(mkpts0.shape,mkpts1.shape)
    n = min(mkpts0.shape[0], mkpts1.shape[0])
    srcImage1_matchedKPs, srcImage2_matchedKPs=[],[]

    if (match_threshold > 1 or match_threshold < 0):
        print("match_threshold error!")

    for i in range(n):
        kp0 = mkpts0[i]
        kp1 = mkpts1[i]
    
        pt0=(kp0[0].item(),kp0[1].item());
        pt1=(kp1[0].item(),kp1[1].item());
        c = confidence[i].item();
        if (c > match_threshold):
            srcImage1_matchedKPs.append(pt0);
            srcImage2_matchedKPs.append(pt1);
    
    return np.array(srcImage1_matchedKPs),np.array(srcImage2_matchedKPs)
pts_src, pts_dst=getGoodMatchPoint(mkpts0, mkpts1, confidence)

h1, status = cv2.findHomography(pts_src, pts_dst, cv.RANSAC, 8)
im_out1 = cv2.warpPerspective(im_dst, h1, (im_dst.shape[1],im_dst.shape[0]))
im_out2 = cv2.warpPerspective(im_res, h1, (im_dst.shape[1],im_dst.shape[0]),16)
#这里 im_res和im_out1是严格配准的状态
myimshowsCL([im_dst,im_out1,im_res,im_out2],rows=2,cols=2, size=6)

此时项目的目录结构如下所示,图中画红框的是项目依赖文件
在这里插入图片描述

5.3 运行效果

代码运行速度信息如下所示,30ms一张图(3060显卡,cuda12,ort17.1【自行编译】)
在这里插入图片描述

点匹配效果如下所示,可以发现针对于近景与远景有不同的匹配关系组,对于这样的数据,是无法进行良好的图像拼接或者重叠区提取的
在这里插入图片描述
重叠区提取效果如下所示
在这里插入图片描述

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

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

相关文章

深入探索 Python 中的数据维数:高维数据处理方法与应用

Python 数据维数 在数据科学和机器学习领域&#xff0c;理解数据的维度是至关重要的。Python作为一种强大而灵活的编程语言&#xff0c;提供了丰富的工具和库来处理各种维度的数据。本文将介绍Python中数据维数的概念&#xff0c;以及如何使用Python库来处理不同维度的数据。 什…

27 防火墙不同区域之间是如何通信

26 华三防火墙安全区域-CSDN博客 目标实现不同区域的通信 1 给防火墙配置IP地址 WEB页面配置IP地址 2 在PC机上配置对应对IP地址 &#xff08;该要启用的接口一定要启用 IP地址 子网掩码 网关 一定要查看好&#xff09; 3 将配置好的IP地址对应的不同接口加入到不同的区域上去 …

关于忠诚:忠于自己的良知、理想、信念

关于忠诚&#xff1a; 当我们面对公司、上司、爱人、恋人、合作伙伴还是某件事&#xff0c;会纠结离开还是留下&#xff0c;这里我们要深知忠诚的定义&#xff0c;我们不是忠诚于某个人、某件事、或者某个机构&#xff0c;而是忠诚于自己的良知&#xff0c;忠诚于自己的理想和…

【计算机毕业设计】020基于weixin小程序订餐系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

分班结果老师怎么发给家长?

分班结果老师怎么发给家长&#xff1f; 随着新学期的脚步渐近&#xff0c;老师们的工作也变得愈发繁忙。从准备教学计划到整理课程材料&#xff0c;每一项任务都不容小觑。而其中&#xff0c;分班结果的告知工作&#xff0c;更是让不少老师头疼不已。传统的分班通知方式&#…

【电路笔记】-AB类放大器

AB类放大器 文章目录 AB类放大器1、概述2、AB类放大器介绍3、AB类放大器效率4、偏置方法4.1 电压偏置4.2 分压网络4.3 电位器偏置4.4 二极管偏置5、二极管网络和电流源6、AB类放大器的电源分配7、总结1、概述 A类放大器提供非常好的输出线性度,这意味着可以忠实地再现信号,但…

Linux——进程间通信一(共享内存、管道、systrem V)

一、进程间通信介绍 1.1、进程间通信的概念和意义 进程间通信(IPC interprocess communication)是一组编程接口&#xff0c;让不同进程之间相互传递、交换信息(让不同的进程看到同一份资源) 数据传输:一个进程需要将它的数据发送给另外一个进程 资源共享:多个进程之间共享同样…

webGL可用的14种3D文件格式,但要具体问题具体分析。

hello&#xff0c;我威斯数据&#xff0c;你在网上看到的各种炫酷的3d交互效果&#xff0c;背后都必须有三维文件支撑&#xff0c;就好比你网页的时候&#xff0c;得有设计稿源文件一样。WebGL是一种基于OpenGL ES 2.0标准的3D图形库&#xff0c;可以在网页上实现硬件加速的3D图…

世界人工智能大会中“数据+标注”相关的关键词浅析

标注猿的第79篇原创 一个用数据视角看AI世界的标注猿 大家好&#xff0c;我是AI数据标注猿刘吉&#xff0c;一个用数据视角看AI世界的标注猿。 在国家级数据标注基地建设任务下发后的两个月时间里&#xff0c;全国各地政府、各个高校都快速行动了起来&#xff0c;数据行…

【Linux】压缩命令——gzip,bzip2,xz

1.压缩文件的用途与技术 你是否有过文件太大&#xff0c;导致无法以正常的E-mail方式发送&#xff1f;又或学校、厂商要求使用CD或DVD来做数据归档之用&#xff0c;但是你的单一文件却都比这些传统的一次性存储媒介还要大&#xff0c;那怎么分成多块来刻录&#xff1f;还有&am…

局部静态变量实现的单例存在多个对象

文章目录 背景测试代码运行测试尝试打开编译器优化进一步分析 背景 业务中出现日志打印失效&#xff0c;发现是因为管理日志对象的单例在运行过程中存在了多例的情况。下面通过还原业务场景来分析该问题。 测试代码 /* A.h */ #ifndef CALSS_A #define CALSS_A#include <…

Docker 容器网络及其配置说明

Docker 容器网络及其配置说明 docker容器网络docker的4种网络模式bridge 模式container模式host 模式none 模式应用场景 docker 容器网络配置Linux 内核实现名称空间的创建创建 Network Namespace操作 Network Namespace 转移设备veth pair创建 veth pair实现 Network Namespac…

nature methods | 11种空间转录组学技术的系统性比较

—DOI: 10.1038/s41592-024-02325-3 Systematic comparison of sequencing-based spatial transcriptomic methods 学习了一下空间转录组技术怎么做benchmark&#xff0c;从多个的角度去考虑目前技术的性能&#xff0c;受益良多。但该研究缺少对10X Visium HD的测评&#xff…

mac怎么压缩pdf文件大小,mac压缩pdf文件大小不改变清晰度

在数字化时代&#xff0c;pdf格式因其良好的兼容性和稳定性&#xff0c;成为了文档分享和传输的首选。然而&#xff0c;随着文件内容的丰富&#xff0c;pdf文件的体积也越来越大&#xff0c;给存储和传输带来了不小的困扰。本文将揭秘几种简单有效的pdf文件压缩方法&#xff0c…

python爬虫入门(一)之HTTP请求和响应

一、爬虫的三个步骤&#xff08;要学习的内容&#xff09; 1、获取网页内容 &#xff08;HTTP请求、Requests库&#xff09; 2、解析网页内容 &#xff08;HTML网页结构、Beautiful Soup库&#xff09; 3、存储或分析数据 b站学习链接&#xff1a; 【【Python爬虫】爆肝两…

Vue3基础知识:组合式API中的provide和inject,他们作用是什么?如何使用?以及案例演示

1.provide和inject相较于父子传递的不同在于provide,inject可以用于跨层级通信&#xff08;通俗易懂的讲就是可以实现爷孙之间的直接信息传递&#xff09;。 1.跨层级传递数据 1.在顶层组件通过provide函数提供数据 2.底层组件通过inject函数获取数据 演示一&#xff1a;跨…

vCenter登录失败报500错误:no healthy upstream

过了个周末登录vCenter的时候提示&#xff1a;HTTP状态500 - 内部服务器错误&#xff1b;重启服务后提示&#xff1a;no healthy upstream。如下图&#xff1a; 看到这个情况&#xff0c;肯定就是部分不服务异常了或者压根就没有启动。至于说因为啥异常还不得而知。想着登录管理…

MSPM0G3507——串口0从数据线传输变为IO口传输

默认的跳线帽时这样的&#xff0c;这样时是数据线传输 需要改成这样&#xff0c;即可用IO口进行数据传输

Spring IOC基于XML和注解管理Bean

IoC 是 Inversion of Control 的简写&#xff0c;译为“ 控制反转 ”&#xff0c;它不是一门技术&#xff0c;而是一种设计思想&#xff0c;是一个重要的面向对象编程法则&#xff0c;能够指导我们如何设计出 松耦合、更优良的程序。 Spring 通过 IoC 容器来管理所有 Java 对象…

【国产AI绘图】快手把“可图”大模型开源了,这是一款支持中文的SDXL模型

Kolors 是由 Kuaishou Kolors 团队&#xff08;快手可图&#xff09;开发的基于潜在扩散的大规模文本到图像生成模型。经过数十亿对文本图像的训练&#xff0c;Kolors 在视觉质量、复杂语义的准确性以及中英文字符的文本渲染方面&#xff0c;与开源和专有模型相比都具有显著优势…