【C++】和【预训练模型】实现【机器学习】【图像分类】的终极指南

news2025/2/22 8:23:10

目录

💗1. 准备工作和环境配置💕

💖安装OpenCV💕

💖安装Dlib💕

下载并编译TensorFlow C++ API💕

💗2. 下载和配置预训练模型💕

💖2.1 下载预训练的ResNet-50模型💕

💖2.2 配置TensorFlow C++ API💕

💖2.3 加载和使用模型💕

💗3.编写代码进行图像分类💕

💖CMakeLists.txt💕

💖main.cpp💕

💗4. 代码分析和推导💕

💖初始化TensorFlow会话💕

💖读取和导入模型💕

💖读取输入图像💕

💖创建输入Tensor💕

💖运行会话并处理输出💕

💗5. 进阶优化与性能提升💕

💖多线程处理💕

💖GPU加速💕

💖模型优化💕

💗6. 问题与解决方案💕

💖问题1:内存不足💕

💖问题2:推理速度慢💕

💖问题3:模型兼容性问题💕

 


 

在现代机器学习和人工智能应用中,图像分类是一个非常常见且重要的任务。通过使用预训练模型,我们可以显著减少训练时间并提高准确性。C++作为一种高效的编程语言,特别适用于需要高性能计算的任务。226b4e959a0c4b4ca7e72460c6008eb7.png

💗1. 准备工作和环境配置💕

首先,我们需要配置开发环境。这里我们将使用以下工具和库:

  • C++ 编译器 (如GCC)
  • CMake 构建系统
  • OpenCV 库
  • Dlib 库
  • 下载并编译C++版本的TensorFlow

💖安装OpenCV💕

在Linux系统上,可以通过以下命令安装OpenCV:

sudo apt-get update
sudo apt-get install libopencv-dev

💖安装Dlib💕

Dlib是一个现代C++工具包,包含了机器学习算法和工具。可以通过以下命令安装:

git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cd build
cmake ..
cmake --build .
sudo make install

下载并编译TensorFlow C++ API💕

下载TensorFlow的C++库并编译,可以参考TensorFlow官方文档进行详细的步骤。确保下载的版本与您当前的环境兼容。

💗2. 下载和配置预训练模型💕

使用ResNet-50模型,这是一个用于图像分类的深度卷积神经网络。在TensorFlow中,可以轻松地获取预训练的ResNet-50模型。以下是下载和配置ResNet-50模型的详细步骤:

💖2.1 下载预训练的ResNet-50模型💕

首先,我们需要下载预训练的ResNet-50模型。TensorFlow提供了很多预训练模型,您可以从TensorFlow的模型库中获取ResNet-50。

1.访问TensorFlow模型库: 打开浏览器,访问TensorFlow模型库的GitHub页面:TensorFlow Model Garden

2.选择预训练模型: 在模型库中找到ResNet-50模型。通常在tensorflow/models/official/vision/image_classification目录下可以找到相关的预训练模型。

3.下载模型文件: 下载模型文件,模型文件通常是一个.pb文件(TensorFlow模型的protobuf格式)。如果直接下载预训练模型文件不方便,可以使用TensorFlow的tf.keras.applications模块直接加载ResNet-50,并保存为.pb文件。

使用Python脚本下载并保存ResNet-50模型:

import tensorflow as tf

model = tf.keras.applications.ResNet50(weights='imagenet')
model.save('resnet50_saved_model', save_format='tf')
  • 运行此脚本将会在当前目录生成一个名为resnet50_saved_model的文件夹,其中包含了模型的.pb文件。

💖2.2 配置TensorFlow C++ API💕

在下载模型文件后,我们需要配置TensorFlow的C++ API来加载和使用该模型。以下是配置步骤:

1.安装TensorFlow C++库: 从TensorFlow的官方网站下载适用于您的平台的TensorFlow C++库。如果没有现成的二进制包,可以从源代码编译TensorFlow C++库。

git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow
./configure
bazel build //tensorflow:libtensorflow_cc.so

编译完成后,库文件位于bazel-bin/tensorflow目录下。

2.设置环境变量: 将TensorFlow C++库的包含路径和库文件路径添加到环境变量中。

export TF_CPP_INCLUDE_DIR=/path/to/tensorflow/include
export TF_CPP_LIB_DIR=/path/to/tensorflow/lib

3.配置CMakeLists.txt: 更新项目的CMakeLists.txt文件,包含TensorFlow C++库的路径。

cmake_minimum_required(VERSION 3.10)
project(ImageClassification)

set(CMAKE_CXX_STANDARD 14)

find_package(OpenCV REQUIRED)
find_package(Dlib REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${Dlib_INCLUDE_DIRS})
include_directories(${TF_CPP_INCLUDE_DIR})
link_directories(${TF_CPP_LIB_DIR})

add_executable(ImageClassification main.cpp)
target_link_libraries(ImageClassification ${OpenCV_LIBS} dlib::dlib tensorflow_cc)

💖2.3 加载和使用模型💕

在完成上述配置后,可以在C++代码中加载和使用ResNet-50模型。下面是示例代码,演示如何加载和使用该模型进行图像分类:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <dlib/dnn.h>
#include <tensorflow/core/public/session.h>
#include <tensorflow/core/protobuf/meta_graph.pb.h>

using namespace std;
using namespace cv;
using namespace tensorflow;

// 定义图像分类函数
void classifyImage(const std::string& model_path, const std::string& image_path) {
    // 初始化TensorFlow会话
    Session* session;
    Status status = NewSession(SessionOptions(), &session);
    if (!status.ok()) {
        std::cerr << "Error creating TensorFlow session: " << status.ToString() << std::endl;
        return;
    }

    // 读取模型
    GraphDef graph_def;
    status = ReadBinaryProto(Env::Default(), model_path, &graph_def);
    if (!status.ok()) {
        std::cerr << "Error reading graph definition from " << model_path << ": " << status.ToString() << std::endl;
        return;
    }

    // 将模型导入会话
    status = session->Create(graph_def);
    if (!status.ok()) {
        std::cerr << "Error creating graph: " << status.ToString() << std::endl;
        return;
    }

    // 读取输入图像
    Mat img = imread(image_path);
    if (img.empty()) {
        std::cerr << "Error reading image: " << image_path << std::endl;
        return;
    }

    // 预处理图像
    Mat img_resized;
    resize(img, img_resized, Size(224, 224));
    img_resized.convertTo(img_resized, CV_32FC3);
    img_resized = img_resized / 255.0;

    // 创建输入Tensor
    Tensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));
    auto input_tensor_mapped = input_tensor.tensor<float, 4>();

    // 将图像数据复制到输入Tensor
    for (int y = 0; y < 224; ++y) {
        for (int x = 0; x < 224; ++x) {
            for (int c = 0; c < 3; ++c) {
                input_tensor_mapped(0, y, x, c) = img_resized.at<Vec3f>(y, x)[c];
            }
        }
    }

    // 运行会话
    std::vector<Tensor> outputs;
    status = session->Run({{"input_tensor", input_tensor}}, {"output_tensor"}, {}, &outputs);
    if (!status.ok()) {
        std::cerr << "Error during inference: " << status.ToString() << std::endl;
        return;
    }

    // 处理输出
    auto output_tensor = outputs[0].tensor<float, 2>();
    int best_label = std::distance(output_tensor(0).data(), std::max_element(output_tensor(0).data(), output_tensor(0).data() + output_tensor.dim_size(1)));

    std::cout << "Predicted label: " << best_label << std::endl;

    // 清理
    session->Close();
    delete session;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <model_path> <image_path>" << std::endl;
        return 1;
    }

    const std::string model_path = argv[1];
    const std::string image_path = argv[2];

    classifyImage(model_path, image_path);

    return 0;
}

💗3.编写代码进行图像分类💕

使用预训练的ResNet-50模型进行图像分类。

💖CMakeLists.txt💕

cmake_minimum_required(VERSION 3.10)
project(ImageClassification)

set(CMAKE_CXX_STANDARD 14)

find_package(OpenCV REQUIRED)
find_package(Dlib REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${Dlib_INCLUDE_DIRS})
include_directories(/path/to/tensorflow/include)
link_directories(/path/to/tensorflow/lib)

add_executable(ImageClassification main.cpp)
target_link_libraries(ImageClassification ${OpenCV_LIBS} dlib::dlib tensorflow)

💖main.cpp💕

#include <iostream>
#include <opencv2/opencv.hpp>
#include <dlib/dnn.h>
#include <tensorflow/core/public/session.h>
#include <tensorflow/core/protobuf/meta_graph.pb.h>

using namespace std;
using namespace cv;
using namespace tensorflow;

// 定义图像分类函数
void classifyImage(const std::string& model_path, const std::string& image_path) {
    // 初始化TensorFlow会话
    Session* session;
    Status status = NewSession(SessionOptions(), &session);
    if (!status.ok()) {
        std::cerr << "Error creating TensorFlow session: " << status.ToString() << std::endl;
        return;
    }

    // 读取模型
    GraphDef graph_def;
    status = ReadBinaryProto(Env::Default(), model_path, &graph_def);
    if (!status.ok()) {
        std::cerr << "Error reading graph definition from " << model_path << ": " << status.ToString() << std::endl;
        return;
    }

    // 将模型导入会话
    status = session->Create(graph_def);
    if (!status.ok()) {
        std::cerr << "Error creating graph: " << status.ToString() << std::endl;
        return;
    }

    // 读取输入图像
    Mat img = imread(image_path);
    if (img.empty()) {
        std::cerr << "Error reading image: " << image_path << std::endl;
        return;
    }

    // 预处理图像
    Mat img_resized;
    resize(img, img_resized, Size(224, 224));
    img_resized.convertTo(img_resized, CV_32FC3);
    img_resized = img_resized / 255.0;

    // 创建输入Tensor
    Tensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));
    auto input_tensor_mapped = input_tensor.tensor<float, 4>();

    // 将图像数据复制到输入Tensor
    for (int y = 0; y < 224; ++y) {
        for (int x = 0; x < 224; ++x) {
            for (int c = 0; c < 3; ++c) {
                input_tensor_mapped(0, y, x, c) = img_resized.at<Vec3f>(y, x)[c];
            }
        }
    }

    // 运行会话
    std::vector<Tensor> outputs;
    status = session->Run({{"input_tensor", input_tensor}}, {"output_tensor"}, {}, &outputs);
    if (!status.ok()) {
        std::cerr << "Error during inference: " << status.ToString() << std::endl;
        return;
    }

    // 处理输出
    auto output_tensor = outputs[0].tensor<float, 2>();
    int best_label = std::distance(output_tensor(0).data(), std::max_element(output_tensor(0).data(), output_tensor(0).data() + output_tensor.dim_size(1)));

    std::cout << "Predicted label: " << best_label << std::endl;

    // 清理
    session->Close();
    delete session;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <model_path> <image_path>" << std::endl;
        return 1;
    }

    const std::string model_path = argv[1];
    const std::string image_path = argv[2];

    classifyImage(model_path, image_path);

    return 0;
}

💗4. 代码分析和推导💕

💖初始化TensorFlow会话💕

首先,我们初始化一个TensorFlow会话。这个会话将用于执行图中的操作。

Session* session;
Status status = NewSession(SessionOptions(), &session);
if (!status.ok()) {
    std::cerr << "Error creating TensorFlow session: " << status.ToString() << std::endl;
    return;
}

💖读取和导入模型💕

使用ReadBinaryProto函数读取二进制格式的模型文件,并将其导入会话。

GraphDef graph_def;
status = ReadBinaryProto(Env::Default(), model_path, &graph_def);
if (!status.ok()) {
    std::cerr << "Error reading graph definition from " << model_path << ": " << status.ToString() << std::endl;
    return;
}

status = session->Create(graph_def);
if (!status.ok()) {
    std::cerr << "Error creating graph: " << status.ToString() << std::endl;
    return;
}

💖读取输入图像💕

我们使用OpenCV读取图像,并将其大小调整为224x224,这是ResNet-50模型所需的输入尺寸。

Mat img = imread(image_path);
if (img.empty()) {
    std::cerr << "Error reading image: " << image_path << std::endl;
    return;
}

Mat img_resized;
resize(img, img_resized, Size(224, 224));
img_resized.convertTo(img_resized, CV_32FC3);
img_resized = img_resized / 255.0;

💖创建输入Tensor💕

接下来,创建一个TensorFlow的Tensor,并将图像数据复制到该Tensor中。

Tensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));
auto input_tensor_mapped = input_tensor.tensor<float, 4>();

for (int y = 0; y < 224; ++y) {
    for (int x = 0; x < 224; ++x) {
        for (int c = 0; c < 3; ++c) {
            input_tensor_mapped(0, y, x, c) = img_resized.at<Vec3f>(y, x)[c];
        }
    }
}

💖运行会话并处理输出💕

使用会话运行模型,并获取输出结果。

std::vector<Tensor> outputs;
status = session->Run({{"input_tensor", input_tensor}}, {"output_tensor"}, {}, &outputs);
if (!status.ok()) {
    std::cerr << "Error during inference: " << status.ToString() << std::endl;
    return;
}

auto output_tensor = outputs[0].tensor<float, 2>();
int best_label = std::distance(output_tensor(0).data(), std::max_element(output_tensor(0).data(), output_tensor(0).data() + output_tensor.dim_size(1)));

std::cout << "Predicted label: " << best_label << std::endl;

💗5. 进阶优化与性能提升💕

在这部分中,我们将探讨如何进一步优化代码以提高性能和效率。这些技巧和方法包括多线程处理、GPU加速、模型优化等。

💖多线程处理💕

在处理大量图像时,利用多线程可以显著提高处理速度。C++中的std::thread库使得多线程编程更加方便。多线程处理:

#include <thread>
#include <vector>

// 定义一个处理图像的函数
void processImage(const std::string& model_path, const std::string& image_path) {
    classifyImage(model_path, image_path);
}

int main(int argc, char** argv) {
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " <model_path> <image_paths...>" << std::endl;
        return 1;
    }

    const std::string model_path = argv[1];
    std::vector<std::string> image_paths;
    for (int i = 2; i < argc; ++i) {
        image_paths.push_back(argv[i]);
    }

    std::vector<std::thread> threads;
    for (const auto& image_path : image_paths) {
        threads.emplace_back(processImage, model_path, image_path);
    }

    for (auto& t : threads) {
        if (t.joinable()) {
            t.join();
        }
    }

    return 0;
}

通过这种方式,我们可以同时处理多个图像,从而提高整体处理效率。

💖GPU加速💕

GPU在处理大规模并行计算任务时具有显著优势。TensorFlow的C++ API支持GPU加速,只需在创建会话时指定GPU设备即可:

SessionOptions options;
options.config.mutable_gpu_options()->set_allow_growth(true);
Session* session;
Status status = NewSession(options, &session);
if (!status.ok()) {
    std::cerr << "Error creating TensorFlow session: " << status.ToString() << std::endl;
    return;
}

在配置好CUDA和cuDNN后,TensorFlow会自动利用GPU进行计算,从而显著提高计算速度。

💖模型优化💕

模型优化是提升推理速度和减少内存占用的重要手段。常用的方法包括模型量化和裁剪。可以使用TensorFlow的模型优化工具进行这些优化。

使用TensorFlow的模型优化API进行量化:

import tensorflow as tf
from tensorflow_model_optimization.quantization.keras import vitis_quantize

model = tf.keras.models.load_model('model.h5')
quantized_model = vitis_quantize.quantize_model(model)
quantized_model.save('quantized_model.h5')

将量化后的模型加载到C++项目中,可以显著减少模型的计算量,从而提高推理速度。

💗6. 问题与解决方案💕

在实际应用中,可能会遇到各种问题。以下是一些常见问题及其解决方案,具体分析每种问题的可能原因和详细的解决步骤。

💖问题1:内存不足💕

解决方案:

1.减少批处理大小: 批处理大小(batch size)是指一次性送入模型进行处理的数据样本数。如果批处理大小过大,可能会导致内存溢出。可以通过减小批处理大小来减少内存使用。例如,将批处理大小从32减小到16甚至更小。

// 将批处理大小设置为1
Tensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));

2.使用模型量化技术: 模型量化通过将浮点数转换为低精度整数来减少模型大小和内存占用。TensorFlow提供了量化工具,可以在训练后对模型进行量化。

import tensorflow as tf
from tensorflow_model_optimization.quantization.keras import vitis_quantize

model = tf.keras.models.load_model('model.h5')
quantized_model = vitis_quantize.quantize_model(model)
quantized_model.save('quantized_model.h5')

3.更高效的数据预处理方法: 使用OpenCV或其他图像处理库进行高效的数据预处理,尽量减少在内存中的图像副本。在读取图像后立即进行缩放和归一化处理。

Mat img = imread(image_path);
resize(img, img_resized, Size(224, 224));
img_resized.convertTo(img_resized, CV_32FC3);
img_resized = img_resized / 255.0;

💖问题2:推理速度慢💕

解决方案:

1.使用GPU加速: GPU在处理大规模并行计算任务时具有显著优势。在TensorFlow中可以通过指定GPU设备来加速推理。

SessionOptions options;
options.config.mutable_gpu_options()->set_allow_growth(true);
Session* session;
Status status = NewSession(options, &session);
if (!status.ok()) {
    std::cerr << "Error creating TensorFlow session: " << status.ToString() << std::endl;
    return;
}

2.利用多线程并行处理: 使用C++的多线程库(如std::thread)来并行处理多个图像,充分利用多核CPU的计算能力。

#include <thread>
#include <vector>

void processImage(const std::string& model_path, const std::string& image_path) {
    classifyImage(model_path, image_path);
}

int main(int argc, char** argv) {
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " <model_path> <image_paths...>" << std::endl;
        return 1;
    }

    const std::string model_path = argv[1];
    std::vector<std::string> image_paths;
    for (int i = 2; i < argc; ++i) {
        image_paths.push_back(argv[i]);
    }

    std::vector<std::thread> threads;
    for (const auto& image_path : image_paths) {
        threads.emplace_back(processImage, model_path, image_path);
    }

    for (auto& t : threads) {
        if (t.joinable()) {
            t.join();
        }
    }

    return 0;
}

3.优化模型结构: 优化模型结构,例如减少模型层数、使用更小的卷积核等,可以提高推理速度。具体方法包括剪枝、合并卷积层等。

4.使用模型量化和裁剪技术: 量化可以显著减少模型大小和计算量,从而提高推理速度。模型裁剪(pruning)通过去除不重要的权重来优化模型。

import tensorflow_model_optimization as tfmot

prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
pruning_params = {
    'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.30,
                                                             final_sparsity=0.70,
                                                             begin_step=2000,
                                                             end_step=10000)
}

model_for_pruning = prune_low_magnitude(model, **pruning_params)
model_for_pruning.compile(optimizer='adam',
                          loss=tf.keras.losses.categorical_crossentropy,
                          metrics=['accuracy'])

model_for_pruning.fit(train_data, train_labels, epochs=2, validation_split=0.1)

💖问题3:模型兼容性问题💕

解决方案:

  1. 确保模型文件和库版本匹配: 在不同平台上使用模型时,确保模型文件与库版本匹配非常重要。例如,TensorFlow模型的版本和TensorFlow库的版本必须一致。

  2. 重新训练和导出模型: 如果遇到兼容性问题,尝试在目标平台上重新训练并导出模型。这样可以确保模型和运行环境的完全兼容。

    import tensorflow as tf
    
    # 重新训练模型
    model = tf.keras.models.Sequential([
        tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(10, activation='softmax')
    ])
    
    model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    model.fit(train_images, train_labels, epochs=10)
    
    # 导出模型
    model.save('retrained_model.h5')
    

    3.使用中间格式进行转换: 使用ONNX(开放神经网络交换)格式,可以在不同的深度学习框架之间转换模型。可以使用tf2onnx将TensorFlow模型转换为ONNX格式,然后在目标平台上加载ONNX模型。

    import tf2onnx
    import tensorflow as tf
    
    model = tf.keras.models.load_model('model.h5')
    spec = (tf.TensorSpec((None, 224, 224, 3), tf.float32, name="input"),)
    output_path = "model.onnx"
    
    model_proto, _ = tf2onnx.convert.from_keras(model, input_signature=spec, opset=13)
    with open(output_path, "wb") as f:
        f.write(model_proto.SerializeToString())
    

    然后在C++中使用ONNX Runtime加载和推理ONNX模型:

    #include <onnxruntime/core/providers/cpu/cpu_provider_factory.h>
    #include <onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.h>
    #include <onnxruntime/core/session/onnxruntime_cxx_api.h>
    
    int main() {
        Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ONNXModel");
    
        Ort::SessionOptions session_options;
        session_options.AppendExecutionProvider_TensorRT();
        session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
    
        Ort::Session session(env, "model.onnx", session_options);
    
        // 输入、输出和推理代码略...
        
        return 0;
    }
    

     

    2abe820ccf5e4af399c6049449f1dd1e.png

 

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

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

相关文章

文章MSM_metagenomics(三):Alpha多样性分析

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 本教程使用基于R的函数来估计微生物群落的香农指数和丰富度&#xff0c;使用MetaPhlAn prof…

热镀锌钢板耐液体性能测 彩钢板抗拉强度检测

钢板检测范围&#xff1a;钢板、彩钢板、不锈钢板、耐磨钢板、合金钢板、压型钢板、冷轧钢板、弹簧钢板、碳钢板、热轧钢板、厚钢板、热镀锌钢板、冲孔钢板、船用钢板、硅钢板、花纹钢板、压力容器钢板、耐候钢板、 钢板检测项目包括化学性能检测、性能检测、机械性能检测、老…

JAVA-CopyOnWrite并发集合

文章目录 JAVA并发集合1_实现原理2_什么是CopyOnWrite?3_CopyOnWriteArrayList的原理4_CopyOnWriteArraySet5_使用场景6_总结 JAVA并发集合 从Java5开始&#xff0c;Java在java.util.concurrent包下提供了大量支持高效并发访问的集合类&#xff0c;它们既能包装良好的访问性能…

SwiGLU激活函数与GLU门控线性单元原理解析

前言 SwiGLU激活函数在PaLM&#xff0c;LLaMA等大模型中有广泛应用&#xff0c;在大部分测评中相较于Transformer FFN中所使用的ReLU函数都有提升。本篇先介绍LLaMA中SwiGLU的实现形式&#xff0c;再追溯到GLU门控线性单元&#xff0c;以及介绍GLU的变种&#xff0c;Swish激活…

phpcms仿蚁乐购淘宝客网站模板

phpcms仿蚁乐购网站模板&#xff0c;淘宝客行业模板免费下载&#xff0c;该模板网站很容易吸引访客点击&#xff0c;提升ip流量和pv是非常有利的。本套模板采用现在非常流行的全屏自适应布局设计&#xff0c;且栏目列表以简洁&#xff0c;非常时尚大气。页面根据分辨率大小而自…

华为北向网管NCE开发教程(7)历史告警采集

1准备工作 准备一个FTP服务器和网管北向网络通&#xff0c;网管北向生成告警文件&#xff0c;会推送到准备的FTP服务器上。 linux&#xff0c;都是自带FTP的&#xff0c;如果是linux则无需自己搭建&#xff0c;如果是windows则需要自己搭建 2生成告警文件 2.1方法说明getAll…

使用libcurl实现简单的HTTP访问

代码; #include <stdio.h> #include <stdlib.h> #include <curl/curl.h> // 包含libcurl库 FILE *fp; // 定义一个文件标识符 size_t write_data(void *ptr,size_t size,size_t nmemb,void *stream) { // 定义回调函数&#xff0c;用于将…

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】 题目描述&#xff1a;解题思路一&#xff1a;滑动窗口与排序解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操…

《华为项目管理之道》第1章笔记

《华为项目管理之道》&#xff0c;是新出的华为官方的项目管理书&#xff0c;整个书不错。第1章的精华&#xff1a; 1.2.2 以项目为中心的机制 伴随着项目型组织的建立&#xff0c;华为逐步形成了完备的项目管理流程和制度&#xff0c;从而将业务运 作构建在项目经营管理之…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 启动多任务排序(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 启动多任务排序(200分) 🌍 评测功能需要订阅专栏后私信联系…

STM32HAL-最简单的时间片论法

目录 概述 一、开发环境 二、STM32CubeMx配置 三、编码 四、运行结果 五、总结 概述 本文章使用最简单的写法时间片论法框架,非常适合移植各类型单片机,特别是资源少的芯片上。接下来将在stm32单片机上实现,只需占用1个定时器作为tick即可。(按键框架+时间片论法)…

cs61C | lecture4

cs61C | lecture4 C 语言内存布局 ### Stack 在最顶部&#xff0c;向下增长。包含局部变量和 function frame information。 > Each stack frame is a contiguous block of memory holding the local variables of a single procedure. > A stack frame includes: > …

Leaflet集成wheelnav在WebGIS中的应用

目录 前言 一、两种错误的实现方式 1、组件不展示 2、意外中的空白 二、不同样式的集成 1、在leaflet中集成wheelnav 2、给marker绑定默认组件 2、面对象绑定组件 3、如何自定义样式 三、总结 前言 在之前的博客中&#xff0c;我们曾经介绍了使用wheelnav.js构建酷炫…

简易开发一个app

即时设计网站 即时设计 - 可实时协作的专业 UI 设计工具 需要先设计好UI界面 上传到codefun 首次需要安装 自动生成代码 打开hb软件 新建项目 打开创建的项目 删除代码 复制代码过去 下载图片 将图片放到文件夹里 改为这种格式 index.vue 如果不需要uni-app导航栏可以修改 …

Vue43-单文件组件

一、脚手架的作用 单文件组件&#xff1a;xxx.vue&#xff0c;浏览器不能直接运行&#xff01;&#xff01;&#xff01; 脚手架去调用webpack等第三方工具。 二、vue文件的命名规则 建议用下面的两种方式。&#xff08;首字母大写&#xff01;&#xff01;&#xff01;&#x…

云原生系列之Docker常用命令

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列文章目录 云原生之…

大模型算法备案全网最详细说明(附附件)

本文要点&#xff1a;大模型备案最详细说明&#xff0c;大模型备案条件有哪些&#xff0c;《算法安全自评估报告》模板&#xff0c;大模型算法备案&#xff0c;大模型上线备案&#xff0c;生成式人工智能(大语言模型)安全评估要点&#xff0c;网信办大模型备案。 共分为以下几…

逻辑这回事(五)---- 资源优化

基础篇 Memory 避免细碎的RAM。将大的RAM拆分成多个小RAM&#xff0c;并根据地址关断可以优化功耗&#xff0c;但把多个小RAM合成大RAM可以优化面积。Block RAM和分布式RAM合理选择。根据存储容量&#xff0c;对Block RAM和分布式RAM的实现面积和功耗进行评估&#xff0c;选择…

「网络原理」IP 协议

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;计网 &#x1f387;欢迎点赞收藏加关注哦&#xff01; IP 协议 &#x1f349;报头结构&#x1f349;地址管理&#x1f34c;动态分配 IP 地址&#x1f34c;NAT 机制&#xff08;网络地址映射&am…

【计算机毕业设计】242基于微信小程序的外卖点餐系统

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