当前位置: 首页 > news >正文

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

目录

💗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 tfmodel = 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;// 创建输入TensorTensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));auto input_tensor_mapped = input_tensor.tensor<float, 4>();// 将图像数据复制到输入Tensorfor (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;// 创建输入TensorTensor input_tensor(DT_FLOAT, TensorShape({1, 224, 224, 3}));auto input_tensor_mapped = input_tensor.tensor<float, 4>();// 将图像数据复制到输入Tensorfor (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_quantizemodel = 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_quantizemodel = 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 tfmotprune_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 tfmodel = 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

 

相关文章:

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

目录 &#x1f497;1. 准备工作和环境配置&#x1f495; &#x1f496;安装OpenCV&#x1f495; &#x1f496;安装Dlib&#x1f495; 下载并编译TensorFlow C API&#x1f495; &#x1f497;2. 下载和配置预训练模型&#x1f495; &#x1f496;2.1 下载预训练的ResNet…...

HTML5 Web SQL数据库:浏览器中的轻量级数据库解决方案

在HTML5时代&#xff0c;Web开发迎来了一系列创新特性&#xff0c;其中之一便是Web SQL数据库。尽管Web SQL标准已被W3C废弃&#xff0c;转而推荐IndexedDB作为替代&#xff0c;但了解Web SQL对于学习Web存储技术的演进历程仍有其价值。本文将详细介绍Web SQL数据库的基本概念、…...

C++ const关键字有多种用法举例

C const关键字有多种用法 可以用来修饰变量、指针、函数参数、成员函数等。可以看到const在C中有多种用法&#xff0c;主要用于保证数据的不可变性&#xff0c;增强代码的安全性和可读性。在实际编程中&#xff0c;根据需要选择适当的const用法&#xff0c;可以有效避免意外修…...

Makefile-快速掌握

引用 本文完全参照大佬的文档写的&#xff0c;写这篇文章只是为了梳理一下知识 https://github.com/marmotedu/geekbang-go/blob/master/makefile/Makefile%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md 介绍 Makefile是一个工程文件的编译规则&#xff0c;描述了整个工程的编译…...

定个小目标之刷LeetCode热题(20)

这题与上一题有一点不同&#xff0c;上一题是判断链表是否存在环&#xff0c;这题是寻找入环的第一个节点&#xff0c;有一个规则是这样的&#xff0c;在存在环的情况下&#xff0c;运用快慢指针判断是否有环结束时&#xff0c;把快指针指向头结点&#xff0c;慢指针不变&#…...

短剧分销小程序:影视产业链中的新兴力量

一、引言 在数字化浪潮的推动下&#xff0c;影视产业正迎来一场深刻的变革。短剧分销小程序作为这场变革中的新兴力量&#xff0c;正以其独特的魅力和价值&#xff0c;逐渐在影视产业链中崭露头角。本文将探讨短剧分销小程序在影视产业链中的新兴地位、其带来的变革以及未来的…...

使用fvm切换flutter版本

切换flutter版本 下载fvm 1、dart pub global activate fvm dart下载fvm 2、warning中获取下载本地的地址 3、添加用户变量path&#xff1a; 下载地址 终端查看fvm版本 fvm --version 4、指定fvm文件缓存地址 fvm config --cache-path C:\src\fvm&#xff08;自定义地址&…...

python通过selenium实现自动登录及轻松过滑块验证、点选验证码(2024-06-14)

一、chromedriver配置环境搭建 请确保下载的驱动程序与你的Chrome浏览器版本匹配&#xff0c;以确保正常运行。 1、Chrome版本号 chrome的地址栏输入chrome://version&#xff0c;自然就得到125.0.6422.142 版本 125.0.6422.142&#xff08;正式版本&#xff09; &#xff08;…...

【C++】开源项目收集

C 是一种强大的、静态类型的通用编程语言&#xff0c;它的开源生态系统非常丰富&#xff0c;拥有众多高质量的项目。以下是一些知名的C开源项目&#xff1a; Boost: 这是一个庞大的库集合&#xff0c;提供了大量的实用工具和组件&#xff0c;如文件系统、网络编程、智能指针等&…...

爬虫相关面试题

一&#xff0c;如何抓取一个网站&#xff1f; 1&#xff0c;去百度和谷歌搜一下这个网站有没有分享要爬取数据的API 2, 看看电脑网页有没有所需要的数据&#xff0c;写代码测试调查好不好拿&#xff0c;如果好拿直接开始爬取 3&#xff0c;看看有没有电脑能打开的手机网页&a…...

Spring Cloud Netflix 之 Ribbon

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言前言1、负载均衡1.1、服务端负载均衡1.2、客户端负载均衡 2、Ribbon实现服务…...

C语言怎样记住那么多的颜⾊?

一、问题 ⾚、橙、⻩、绿、⻘、蓝、紫&#xff0c;如此之多的颜⾊&#xff0c;数字不好记&#xff0c;英⽂看程序还可以&#xff0c; 直接写也不好写。那么怎样记住那么多的颜⾊呢&#xff1f; 二、解答 颜⾊枚举值如下&#xff1a; enum COLORS {BLACK, /*O⿊*/BLUE, …...

LabVIEW软件开发任务的工作量估算方法

在开发LabVIEW软件时&#xff0c;如何准确估算软件开发任务的工作量。通过需求分析、功能分解、复杂度评估和资源配置等步骤&#xff0c;结合常见的估算方法&#xff0c;如专家判断法、类比估算法和参数估算法&#xff0c;确保项目按时按质完成&#xff0c;提供项目管理和资源分…...

【已解决】引入 element 组件无法使用编译错误 ERROR Failed to compile with 1 error

如果大家使用这个vue 配合 element 框架不熟练&#xff0c;当你顺利按照文档安装好 vue 和 element 的时候想要使用element 的组件时候确无法展示出来&#xff0c;甚至报错。不妨看看是不是这个问题&#xff0c; 1.首先使用element 的时候&#xff0c;前提是把必须要的 elemen…...

Prometheus的四种指标类型

目录 一、Counter 计数器 1.1Counter 是计数器类型 1.2Counter 类型示例 二、Gauge 仪表盘 2.1Gauge是测量器类型 2.2Gauge 类型示例 三、Histogram 累积直方图 3.1Histogram 作用及特点 3.2使用 histogram 柱状图 四、Summary 摘要 一、Counter 计数器 1.1Counter …...

FastDFS SpringBoot 客户端 Demo搭建,支持文件上传下载

一、准备 fastdfs-client-java 依赖包 1、从 Git 下载 FastDFS java client SDK 源码 https://github.com/happyfish100/fastdfs-client-java.git<fastdfs-client-java 源码见附件> 2、使用ant从源码构建 ant clean package3、使用maven从源码安装 mvn clean instal…...

十大成长型思维:定位思维、商业思维、时间管理思维、学习成长思维、精力管理思维、逻辑表达思维、聚焦思维、金字塔原理、目标思维、反思思维

一、定位思维 定位思维是一种在商业和管理领域中至关重要的思维模式&#xff0c;它涉及到如何在顾客心智中确立品牌的独特位置&#xff0c;并使其与竞争对手区分开来。以下是关于定位思维的清晰介绍&#xff1a; 1、定义 定位思维是一种从潜在顾客的心理认知出发&#xff0c;通…...

GraphQL(9):Spring Boot集成Graphql简单实例

1 安装插件 我这边使用的是IDEA&#xff0c;需要先按照Graphql插件&#xff0c;步骤如下&#xff1a; &#xff08;1&#xff09;打开插件管理 在IDEA中&#xff0c;打开主菜单&#xff0c;选择 "File" -> "Settings" (或者使用快捷键 Ctrl Alt S …...

vue3+ Element-Plus 点击勾选框往input中动态添加多个tag

实现效果&#xff1a; template&#xff1a; <!--产品白名单--><div class"con-item" v-if"current 0"><el-form-item label"平台名称"><div class"contaion" click"onclick"><!-- 生成的标签 …...

唯美仙侠手游【九幽仙域】win服务端+GM后台+详细教程

资源下载地址&#xff1a;九幽仙域搭建-...

Qt creator day2练习

使用手动连接&#xff0c;将登录框中的取消按钮使用第二种方式&#xff0c;右击转到槽&#xff0c;在该函数中&#xff0c;调用关闭函数&#xff0c;将登录按钮使用Qt4版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为“admin”&#xff0c;密…...

哪里有海量的短视频素材,以及短视频制作教程?

在当下&#xff0c;短视频已成为最火爆的内容形式之一&#xff0c;尤其是在抖音上。但很多创作者都面临一个问题&#xff1a;视频素材从哪里来&#xff1f;怎么拍摄才能吸引更多观众&#xff1f;别担心&#xff0c;今天我将为大家推荐几个宝藏网站&#xff0c;确保你素材多到用…...

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

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

Web前端与其他前端:深度对比与差异性剖析

Web前端与其他前端&#xff1a;深度对比与差异性剖析 在快速发展的前端技术领域&#xff0c;Web前端无疑是其中最耀眼的明星。然而&#xff0c;当我们谈论前端时&#xff0c;是否仅仅指的是Web前端&#xff1f;实际上&#xff0c;前端技术还包括了许多其他细分领域。本文将从四…...

AI 客服定制:LangChain集成订单能力

为了提高AI客服的问题解决能力&#xff0c;我们引入了LangChain自定义能力&#xff0c;并集成了订单能力。这使得AI客服可以根据用户提出的问题&#xff0c;自动调用订单接口&#xff0c;获取订单信息&#xff0c;并结合文本知识库内容进行回答。这种能力的应用&#xff0c;使得…...

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

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

java程序监控linux服务器硬件,cpu、mem、disk等

实现 使用Oshi和Hutool工具包1、pom依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.github.oshi</groupId>&l…...

高考报志愿闲谈

当你的朋友在选择大学和专业时寻求建议&#xff0c;作为一名研究生并有高考经验的人&#xff0c;你可以提供一些有价值的见解和建议。 兴趣与职业目标&#xff1a; 首先询问他对哪些工科领域感兴趣&#xff0c;如机械工程、电子工程、计算机科学等。探讨他的职业目标。了解他将…...

面试官考我Object类中的所有方法及场景使用?我...

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java 知识点啦&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好习惯&a…...

Web前端精通教程:深入探索与实战指南

Web前端精通教程&#xff1a;深入探索与实战指南 在数字化时代&#xff0c;Web前端技术已经成为构建优秀用户体验的基石。想要精通Web前端&#xff0c;不仅需要掌握扎实的基础知识&#xff0c;还需要具备丰富的实战经验和深入的思考。本文将从四个方面、五个方面、六个方面和七…...