QT调用torch的环境配置(2023.7.19 / Win10+Qt+libtorch(1.9.1)+cuda11.1+cuDNN v8.0.4)

QT/C++成功调用libtorch的环境配置(2023.7.19)

  • QT/C++成功调用libtorch的环境配置
    • Pytorch 模型训练
      • 下载
      • 训练
      • 转化
    • libtorch模型使用
      • 下载
      • C++使用
      • Qt使用
    • 最后的话

QT/C++成功调用libtorch的环境配置

背景:和同门一起搭的新系统是基于QT的,如果系统能够直接调用训练好的神经网络,可以提高图像处理的稳定性和速度。之前听说pytorch训练的权重文件可以直接用C的libtorch调用,速度和直接用python的差不多,这不得试试嘛。避坑无数后,在Qt上测试图像分类和图像分割都OK。

版本:
系统:win10
显卡:3080 Ti+cuda11.1+cuDNN v8.0.4
torch: 1.9.1+cu111
QT: 版本6,64位程序

比较深刻的

  1. 使用和训练网络时,环境对应的pytorch和libtorch版本,以及相应GPU的版本要对应的很好。
  2. 不管是C++还是Qt,想要成功调用libtorch网络模型,都需要加上一句奇妙的咒语。
  3. 如果程序能顺利运行,但网络预测的结果不对,考虑是网络输出前后的数据处理问题。

Pytorch 模型训练

下载

训练运行使用的Pytorch和Libtorch版本,以及相应GPU的版本要对应。
Pytorch下载官网:https://pytorch.org/
考虑到CUDA,我下载的pytorch不是最新版本,过去的合适版本可在https://pytorch.org/get-started/previous-versions/#v182-with-lts-support中找到,并pip下载。
在这里插入图片描述

训练

用了图像分类的训练代码做测试,运行简单,训练快。
图像分割用的U-net类方法。

贴上图像分类代码:

import torch
import torch.nn as nn
from torch import optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
from tqdm import tqdm

'''定义超参数'''
batch_size = 256  # 批的大小
learning_rate = 1e-3  # 学习率
num_epoches = 100  # 遍历训练集的次数

'''
transform = transforms.Compose([
    transforms.RandomSizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean = [ 0.485, 0.456, 0.406 ],
                         std  = [ 0.229, 0.224, 0.225 ]),
    ])
'''

'''下载训练集 CIFAR-10 10分类训练集'''
train_dataset = datasets.CIFAR10('./data', train=True, transform=transforms.ToTensor(), download=True)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = datasets.CIFAR10('./data', train=False, transform=transforms.ToTensor(), download=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

'''定义网络模型'''


class VGG16(nn.Module):
    def __init__(self, num_classes=10):
        super(VGG16, self).__init__()
        self.features = nn.Sequential(
            # 1
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            # 2
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 3
            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            # 4
            nn.Conv2d(128, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 5
            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            # 6
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            # 7
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 8
            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 9
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 10
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 11
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 12
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 13
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.AvgPool2d(kernel_size=1, stride=1),
        )
        self.classifier = nn.Sequential(
            # 14
            nn.Linear(512, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            # 15
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            # 16
            nn.Linear(4096, num_classes),
        )
        # self.classifier = nn.Linear(512, 10)

    def forward(self, x):
        out = self.features(x)
        #        print(out.shape)
        out = out.view(out.size(0), -1)
        #        print(out.shape)
        out = self.classifier(out)
        #        print(out.shape)
        return out


'''创建model实例对象,并检测是否支持使用GPU'''
model = VGG16()
use_gpu = torch.cuda.is_available()  # 判断是否有GPU加速
if use_gpu:
    model = model.cuda()

'''定义loss和optimizer'''
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)

'''训练模型'''

for epoch in range(num_epoches):
    print('*' * 25, 'epoch {}'.format(epoch + 1), '*' * 25)  # .format为输出格式,formet括号里的即为左边花括号的输出
    running_loss = 0.0
    running_acc = 0.0
    for i, data in tqdm(enumerate(train_loader, 1)):

        img, label = data
        # cuda
        if use_gpu:
            img = img.cuda()
            label = label.cuda()
        img = Variable(img)
        label = Variable(label)
        # 向前传播
        out = model(img)
        loss = criterion(out, label)
        running_loss += loss.item() * label.size(0)
        _, pred = torch.max(out, 1)  # 预测最大值所在的位置标签
        num_correct = (pred == label).sum()
        accuracy = (pred == label).float().mean()
        running_acc += num_correct.item()
        # 向后传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print('Finish {} epoch, Loss: {:.6f}, Acc: {:.6f}'.format(
        epoch + 1, running_loss / (len(train_dataset)), running_acc / (len(train_dataset))))

    model.eval()  # 模型评估
    eval_loss = 0
    eval_acc = 0
    for data in test_loader:  # 测试模型
        img, label = data
        if use_gpu:
            img = Variable(img, volatile=True).cuda()
            label = Variable(label, volatile=True).cuda()
        else:
            img = Variable(img, volatile=True)
            label = Variable(label, volatile=True)
        out = model(img)
        loss = criterion(out, label)
        eval_loss += loss.item() * label.size(0)
        _, pred = torch.max(out, 1)
        num_correct = (pred == label).sum()
        eval_acc += num_correct.item()
    print('Test Loss: {:.6f}, Acc: {:.6f}'.format(eval_loss / (len(
        test_dataset)), eval_acc / (len(test_dataset))))
    print()

# 保存模型
torch.save(model.state_dict(), './cnn.pth')

转化

我的模型训练出来是.pth的权重文件,这类文件不能直接被libtorch读取,所以先在pytorch上用torch.jit.trace把.pth转化为.pt文件。
顺便一提,同门的测试,YOLO的pytorch直接训练输出的.pt文件似乎不能直接被libtorch读取,目前只有.pth转换后的.pt可测试成功。

模型转换代码仍参考:
注意:转换需要训练网络的模型结构;转换时是否GPU对输出的.pt文件有影响。

import torch
import torch.nn as nn
from torch import optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
from tqdm import tqdm

print(torch.cuda.device_count())

class VGG16(nn.Module):
    def __init__(self, num_classes=10):
        super(VGG16, self).__init__()
        self.features = nn.Sequential(
            # 1
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            # 2
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 3
            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            # 4
            nn.Conv2d(128, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 5
            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            # 6
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            # 7
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 8
            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 9
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 10
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # 11
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 12
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            # 13
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.AvgPool2d(kernel_size=1, stride=1),
        )
        self.classifier = nn.Sequential(
            # 14
            nn.Linear(512, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            # 15
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            # 16
            nn.Linear(4096, num_classes),
        )
        # self.classifier = nn.Linear(512, 10)

    def forward(self, x):
        out = self.features(x)
        #        print(out.shape)
        out = out.view(out.size(0), -1)
        #        print(out.shape)
        out = self.classifier(out)
        #        print(out.shape)
        return out


'''创建model实例对象,并检测是否支持使用GPU'''
model = VGG16()

use_gpu = torch.cuda.is_available()  # 判断是否有GPU加速
use_gpu = 1
if use_gpu:
    model = model.cuda()
    print("model.cuda")

model.eval()

'''测试'''
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

# 转换模型
model.load_state_dict(torch.load("cnn.pth",map_location=lambda storage, loc: storage.cuda(0)) )
torch.no_grad()
# An example input you would normally provide to your model's forward() method.
example = torch.rand(1, 3, 32, 32)

if use_gpu:
    example = Variable(example).cuda()
    # label = Variable(label, volatile=True).cuda()
else:
    example = Variable(example)
    # label = Variable(label)

# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save("cnn.pt")

libtorch模型使用

下载

libtorch的下载流程可参考。

注意

  • 下载的Release version 和 Debug version关系到使用C或QT的 Release还是Debug模式才能运行成功,注意对应。
  • libtorch对应pytorch同样不是最新版本,可以使用下载链接https://download.pytorch.org/libtorch/cu111/libtorch-win-shared-with-deps-1.9.1%2Bcu111.zip 按格式修改成pytorch 对应版本(即修改链接中的cu版本和torch版本)下载

在这里插入图片描述
解压后得到可使用的库

C++使用

我使用VS2019,libtorch基本的使用方法和一般库一样。

  1. 两个包含目录:
 1. D:\libtorch-win-shared-with-deps-1.9.1+cu111\libtorch\include\torch\csrc\api\include
 2. D:\libtorch-win-shared-with-deps-1.9.1+cu111\libtorch\include
  1. 一个库目录:
 1. D:\libtorch-win-shared-with-deps-1.9.1+cu111\libtorch\lib
  1. 一堆链接器->输入->附加依赖项:
    (注意加全)
asmjit.lib c10.lib c10_cuda.lib caffe2_detectron_ops_gpu.lib
caffe2_module_test_dynamic.lib caffe2_nvrtc.lib
Caffe2_perfkernels_avx.lib Caffe2_perfkernels_avx2.lib
Caffe2_perfkernels_avx512.lib clog.lib cpuinfo.lib dnnl.lib
fbgemm.lib fbjni.lib kineto.lib libprotobuf.lib libprotobuf-lite.lib
libprotoc.lib mkldnn.lib pthreadpool.lib pytorch_jni.lib torch.lib
torch_cpu.lib torch_cuda.lib torch_cuda_cpp.lib torch_cuda_cu.lib
XNNPACK.lib
  1. 一句神奇的魔法咒语,链接器->命令行->其它选项:
    大多数贴出的/INCLUDE:?warp_size@cuda@at@@YAHXZ 我用着不行,参考知乎讨论修改为:
 1. /INCLUDE:"?ignore_this_library_placeholder@@YAHXZ 
  1. 把libtorch相关的dll文件全部扔进项目里,丑陋但能用:
    在这里插入图片描述
  2. 贴入代码

代码是图像分类的,分类之前会确定是否检测到电脑中配置的CUDA,并计算预测速度。
运行要使用GPU用 at::kCUDA,使用CPU则对应修改为at::kCPU

#include "torch/script.h" // One-stop header. 
#include <torch/torch.h>
#include <iostream> 
#include <opencv2\opencv.hpp> 
#include <opencv2\imgproc\types_c.h> 
#include<time.h>  
using namespace cv;
using namespace std;


int main()
{
    /*******load*********/
    auto image = imread("dog3.jpg");
    imshow("testimg1", image);
    waitKey(0);
    
    torch::DeviceType device_type;
    device_type = at::kCUDA;
    torch::Device device(device_type);

    std::cout << "cuDNN : " << torch::cuda::cudnn_is_available() << std::endl;
    std::cout << "CUDA : " << torch::cuda::is_available() << std::endl;
    std::cout << "Device count : " << torch::cuda::device_count() << std::endl;


    torch::jit::script::Module module;
    //std::shared_ptr<torch::jit::script::Module> module = torch::jit::load(argv[1], device);
    try {
        module = torch::jit::load("cpu.pt", device);
    }
    catch (const c10::Error& e) {
        std::cerr << "error loading the model\n";
        return -1;
    }
    vector<string> out_list = { "plane", "ca", "bird", "cat","deer", "dog", "frog", "horse", "ship", "truck" };
    
    if (!image.data)
    {
        cout << "image imread failed" << endl;
    }
    cvtColor(image, image, CV_BGR2RGB);
    Mat img_transfomed;
    resize(image, img_transfomed, Size(32, 32));

    torch::Tensor tensor_image = torch::from_blob(img_transfomed.data, { img_transfomed.rows, img_transfomed.cols, img_transfomed.channels() }, torch::kByte);

    tensor_image = tensor_image.permute({ 2, 0, 1 });
    tensor_image = tensor_image.toType(torch::kFloat);
    tensor_image = tensor_image.div(255);
    tensor_image = tensor_image.unsqueeze(0).to(at::kCUDA);//����һά����չά�ȣ�����ǰ��
    std::vector<torch::jit::IValue> inputs;
    inputs.push_back(tensor_image);
    torch::Tensor output;
    clock_t start_time = clock();
    for (int i = 1; i <= 1000; i++)
    {
        cout << i << endl;
    output = module.forward(inputs).toTensor().to(at::kCUDA);
    
    clock_t end_time = clock();
    cout << "Running time is: " << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间
    start_time = clock();
    }
    torch::Tensor output_max = output.argmax(1);
    int a = output_max.item().toInt();
    cout << "分类预测的结果为:" << out_list[a] << endl;


    return 0;
}
  1. 运行
    运行是Debug还是Release需要注意对应libtorch版本。
    运行可能会遇到各种问题,需要一步步排查,从代码能运行->能CPU读取权重->能GPU读取权重->模型能输出对的结果。
    问题: Torch使用GPU时似乎需要预热,前一两轮预测花费的时间特别长,后续逐渐稳定,不知道有没有改善方法。
    在这里插入图片描述

Qt使用

下载和使用的代码与C++基本不变。

QT的配置上有所差异,体现为.pro文件的配置语法

注意(奇怪的脾气):

  1. 加入lib要一个一个加,/*是不行的
  2. 如果出现dll相关报错,把dll放入项目中
  3. 别忘了奇妙的咒语:LIBS += -INCLUDE:“?ignore_this_library_placeholder@@YAHXZ”
INCLUDEPATH += D:/libtorch-win-shared-with-deps-1.9.1+cu111/libtorch/include
INCLUDEPATH += D:/libtorch-win-shared-with-deps-1.9.1+cu111/libtorch/include/torch/csrc/api/include
LIBS += -LD:/libtorch-win-shared-with-deps-1.9.1+cu111/libtorch/lib \
        -lasmjit \
        -lc10 \
        -lc10_cuda \
        -lcaffe2_detectron_ops_gpu \
        -lcaffe2_module_test_dynamic \
        -lcaffe2_nvrtc \
        -lCaffe2_perfkernels_avx \
        -lCaffe2_perfkernels_avx2 \
        -lCaffe2_perfkernels_avx512 \
        -lclog \
        -lcpuinfo \
        -ldnnl \
        -lfbgemm \
        -lfbjni \
        -lkineto \
        -llibprotobuf \
        -llibprotobuf-lite \
        -llibprotoc \
        -lmkldnn \
        -lpthreadpool \
        -lpytorch_jni \
        -ltorch \
        -ltorch_cpu \
        -ltorch_cuda \
        -ltorch_cuda_cpp \
        -ltorch_cuda_cu \
        -lXNNPACK
LIBS += -INCLUDE:"?ignore_this_library_placeholder@@YAHXZ"

最后的话

对于训练的不同功能的模型,如果不处理好对应模型的输入数据和输出数据,可能会出现无意义的结果,比如全黑图像。

如果本博客有任何错误或需要补充的内容,也欢迎留言分享,我会加以更正。

最后祝大家都能配置好环境,实现想要的功能!

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

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

相关文章

Monocular 3D Object Detection with Depth from Motion 论文学习

论文链接&#xff1a;Monocular 3D Object Detection with Depth from Motion 1. 解决了什么问题&#xff1f; 从单目输入感知 3D 目标对于自动驾驶非常重要&#xff0c;因为单目 3D 的成本要比多传感器的方案低许多。但单目方法很难取得令人满意的效果&#xff0c;因为单张图…

NAT技术是什么?谈谈它的实现方式、优缺点以及作用

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 前言 随着网络的不断发展&#xff0c;网络的应用也越来越多&#xff0c;有限的IPV4地址就显得不怎么够用&#xff0c;所以出现了NAT技术&…

Rust 数据类型 之 结构体(Struct)

目录 结构体&#xff08;Struct&#xff09; 定义与声明 结构体定义 结构体实例 结构体分类 单元结构体&#xff08;Unit Struct&#xff09; 元组结构体&#xff08;Tuple Struct&#xff09; 具名结构体&#xff08;Named Struct&#xff09; 结构体嵌套 结构体方法…

jenkins war包 centos启动安装指导

文章目录 步骤1&#xff1a;进入官网&#xff0c;下载到Jenkins的war包1.1 放置在指定位置1.2 放置安装包和创建文件放置路径1.3 检查环境1.4 配置启动命令和结束命令 步骤2&#xff1a; 启动后进入到Jenkins页面2.1 安装插件&#xff0c;例如流水线2.2 依然出现安装插件失败的…

疑问:为什么我的手机不能同时放两张电信卡呢?联通移动可以

很多后台的小伙伴私信我&#xff1a;“为什么我的双卡双待手机不能用两张电信卡呢&#xff1f;”其实我一直在认真的去查证这个问题&#xff0c;因为现在普遍网上的大流量手机卡套餐&#xff0c;电信是主力&#xff0c;如果第一张卡是电信&#xff0c;第二张卡不能使用电信了&a…

公网访问的Linux CentOS本地Web站点搭建指南

文章目录 前言1. 本地搭建web站点2. 测试局域网访问3. 公开本地web网站3.1 安装cpolar内网穿透3.2 创建http隧道&#xff0c;指向本地80端口3.3 配置后台服务 4. 配置固定二级子域名5. 测试使用固定二级子域名访问本地web站点 前言 在web项目中,部署的web站点需要被外部访问,则…

ES6基础知识一:说说var、let、const之间的区别

一、var 在ES5中&#xff0c;顶层对象的属性和全局变量是等价的&#xff0c;用var声明的变量既是全局变量&#xff0c;也是顶层变量 注意&#xff1a;顶层对象&#xff0c;在浏览器环境指的是window对象&#xff0c;在 Node 指的是global对象 var a 10; console.log(window.…

uview2.0使用u-calendar 的formatter属性,在formatter方法里无法访问this的bug,解决办法!!!!

uview 版本2.0.36 文档 使用该文档的案例&#xff0c;在 formatter打印this也会是undefined。 自己写了个demo 父给子传值v-bind传一个函数&#xff0c;然后在这个函数里面打印this&#xff0c;this是子组件的实例&#xff0c;但是不知道为什么formatter里会打印undefined。希…

微服务 云原生:搭建 K8S 集群

为节约时间和成本&#xff0c;仅供学习使用&#xff0c;直接在两台虚拟机上模拟 K8S 集群搭建 踩坑之旅 系统环境&#xff1a;CentOS-7-x86_64-Minimal-2009 镜像&#xff0c;为方便起见&#xff0c;直接在 root 账户下操作&#xff0c;现实情况最好不要这样做。 基础准备 关…

IntelliJ IDEA Copyright添加

IDEA代码文件的版权(copyright)信息配置 1. 快速创建Copyright 版权配置文件 1.1 创建copyright文件 依次点击 File > Settings… > Editor > Copyright > 点击 “” 号或 “Add profile”***&#xff0c;弹出创建 Copyright Profile 操作窗口&#xff0c;在***文…

低代码如何帮助企业数字化转型?

在数字化时代背景下&#xff0c;企业都面临着巨大的数字化转型挑战。为了迎接这一挑战&#xff0c;企业软件开发工具和平台都在不断地创新和进化。其中&#xff0c;低代码开发平台应运而生&#xff0c;并成为了众多企业转型的首选方案。企业为什么都选择低代码开发平台&#xf…

【基于CentOS 7 的NFS服务】

目录 一、概述 二、应用场景 三、安装 四、启动服务 五、目录结构 1.nfs的主配置文件 2.存储配置文件 六、命令解析 1.共享存储管理命令 2.共享目录查看 七、配置 八、客户端访问 1.查看nfs服务器的共享目录 2.挂载 九、实际案例 一、概述 network filesystemt…

【GitOps系列】使用Kustomize和Helm定义应用配置

文章目录 使用 Kustomize 定义应用改造示例应用1.创建基准和多环境目录2.环境差异分析3.为 Base 目录创建通用 Manifest4.为开发环境目录创建差异 Manifest5.为预发布环境创建差异 Manifest6.为生产环境创建差异 Manifest 部署 Kustomize 应用部署到开发环境部署到生产环境 使用…

Flink笔记

Flink笔记 2.Flink学习笔记2.1流式处理对比2.2 Flink核心概念2.2.1并行度2.2.2算子链2.2.3任务槽 2.3 DataStream2.3.2 读取数据源-源算子&#xff08;Source&#xff09;2.3.3 转换算子&#xff08;Transformation&#xff09; 2.Flink学习笔记 2.1流式处理对比 学习Spark S…

ubuntu22.04上如何创建有privilege权限,有固定自定义IP的空容器

需求背景&#xff1a; 我想用docker来隔离自己的主机环境&#xff0c;来创建一个隔离的空白全新的开发环境&#xff0c;并且使之有固定的IP&#xff0c;在里面可以自由更新下载各种编译依赖&#xff0c;具有privileged权限的容器&#xff0c;以下是操作实现的具体步骤 查看do…

1.12 springboot 整合log4j打印日志

1.除去springboot自带的日志 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><!-- 除去springboot自带的日志 --><exclusion><groupId>org.sprin…

在vscode中运行Hbuilder创建的项目

想必习惯使用vscode的人突然使用HBuilder很不习惯吧&#xff0c;但是HBuilder创建的项目本身没有调试功能。当你有一个app项目但又不想使用HBuilder编写&#xff0c;需要浏览器调试的时候&#xff0c;你这时就需要一个插件了&#xff1a;uni run 插件 基于HBuilderX的采用unia…

JVM运行时区域——对象创建内存分配过程

新创建的对象&#xff0c;都存放在伊甸园区域&#xff0c;当垃圾回收时&#xff0c;将伊甸园区域的垃圾数据销毁&#xff0c;然后将存活的对象转移到幸存者0区域&#xff0c;之后创建的新的对象还是存放在伊甸园区域&#xff0c;等到再次垃圾回收后&#xff0c;将伊甸园区域和幸…

Aurix TC3xx系列MCU ADC采集时间计算方法(四)

文章目录 1 前言2 各阶段时间的计算方法2.1 计算公式2.2 采样阶段2.3 转换阶段2.4 降噪阶段2.5 校准阶段3 采集时间示例>>返回总目录<< 1 前言 在项目开发前期评估阶段,会比较关注ADC的采集时间,我们可以给出一个大概的采样的时间0.5us~1.2us左右,但是对于精确…

SpringCloud nacos 集成 feign 实例

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…