简介
楼主在这一年从事的图像实时检测中涉及到深度学习的内容,于是在没有积累的情况下自己探索了三种方法,接下来分为三篇文章依次进行介绍并对比分析它们的优点。
目前使用比较广泛的深度学习框架有pytorch和TensorFlow两种,我选择使用的是pytorch,但原本的工程是基于C++实现的,为了适配于pytorch我发现了libtorch。libtorch可以说是pytorch的C++移植版本,其安装和使用简单,也不需要复杂的环境配置。本文章将介绍如何用libtorch实现构建神经网络并且加载模型进行预测。
libtorch安装
在pytorch官网我们可以直接下载libtorch的发行版本,这里提供CPU版本的下载地址
https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-1.9.0%2Bcpu.zip
直接下载压缩包后解压即可
官方有提供cmake链接libtorch库的教程,大家可以参考教程进行配置,这里也简单介绍以下。
项目工程的cmakelists下链接libtorch只需要完成下列几个步骤:
1.指定libtorch目录
set(CMAKE_PREFIX_PATH ~/libtorch)
2.搜索libtorch的package
find_package(Torch REQUIRED)
3.链接libtorch库
target_link_libraries(需要链接库的名称 Libtorch)
4.检验是否配置成功
运行下列cpp代码:
#include <torch/torch.h>
#include <iostream>
int main() {
torch::Tensor tensor = torch::rand({2, 3});
std::cout << tensor << std::endl;
}
若结果为:
0.2063 0.6593 0.0866
0.0796 0.5841 0.1569
即配置成功。
libtorch构建网络
这里简要介绍一下libtorch构建神经网络的方法,以简单的LeNet5网络为例:
调用libtorch我们需要先引入两个头文件
#include <torch/script.h> // One-stop header.
#include <torch/torch.h>
定义网络结构并封装成库
struct LeNet5 : torch::nn::Module
{
LeNet5(){};
LeNet5(int num_class, int padding);
torch::Tensor forward(torch::Tensor X);
torch::nn::Conv2d C1{nullptr};
torch::nn::Conv2d C2{nullptr};
torch::nn::Linear FC1{nullptr};
torch::nn::Linear FC2{nullptr};
torch::nn::Linear FC3{nullptr};
void Train();
void Test(const string& address);
void SaveModel(torch::serialize::OutputArchive& archive, const string& path);
};
网络结构的内部实现
/**
* @brief LeNet5 构造函数
* 共七层
* @note
*/
LeNet5::LeNet5(int num_class, int padding)
{
this->C1 = register_module("C1", torch::nn::Conv2d(torch::nn::Conv2dOptions(1, 6, {5, 5}).padding(padding)));
this->C2 = register_module("C2", torch::nn::Conv2d(torch::nn::Conv2dOptions(6, 16, {5, 5})));
this->FC1 = register_module("FC1", torch::nn::Linear(torch::nn::LinearOptions(400, 120)));
this->FC2 = register_module("FC2", torch::nn::Linear(torch::nn::LinearOptions(120, 84)));
this->FC3 = register_module("FC3", torch::nn::Linear(torch::nn::LinearOptions(84, num_class)));
}
/**
* @brief 前馈函数,计算权重
*/
torch::Tensor LeNet5::forward(torch::Tensor X)
{
//卷积池化层
X = this->C1->forward(X);
X = torch::nn::functional::relu(X);
//最大池化
X = torch::max_pool2d(X, {2, 2}, 2);
X = this->C2->forward(X);
X = torch::nn::functional::relu(X);
//最大池化
X = torch::max_pool2d(X, {2, 2}, 2);
//全连接层
X = X.view({X.size(0), -1});
X = FC1->forward(X);
X = torch::nn::functional::relu(X);
X = FC2->forward(X);
X = torch::nn::functional::relu(X);
X = FC3->forward(X);
return X;
}
损失函数和优化器
损失函数可以在torch::nn中选择,优化器在torch::optim中也有定义,示例:
// 损失函数定义成交叉熵损失
auto criterion = torch::nn::CrossEntropyLoss();
// 优化器选择SGD优化器
auto optimizer = torch::optim::SGD(this->parameters(), torch::optim::SGDOptions(0.005).momentum(0.9));
保存模型
libtorch的模型需要保存为torch::serialize::OutputArchive类型,所以可以参考一下方法:
// 实例化保存模型类型
torch::serialize::OutputArchive archive;
// 保存模型参数
this->save(archive);
// 设置保存路径
archive.save_to(path);
总结
libtorch虽然使用简单方便,但是对于深度学习领域C++对比Python本就不占优势,且移植过程也有很多不适配的地方,所以libtorch在一些方面性能上略差于原本的pytorch,对于实时要求很高的检测中并不适用。
参考内容
INSTALLING C++ DISTRIBUTIONS OF PYTORCH