问题:Segmentation 错误。在 C++ API 上使用自定义 onnx 模型运行。模型在 Python 上按预期工作,但在 C++ API 上运行相同的模型时,会收到一个分段错误
python的模型代码如下:
class Facenet(nn.Module):
def __init__(self, backbone="mobilenet", dropout_keep_prob=0.5, embedding_size=128, num_classes=None, pretrained=False):
super(Facenet, self).__init__()
if backbone == "mobilenet":
self.backbone = mobilenet(pretrained)
flat_shape = 1024
elif backbone == "inception_resnetv1":
self.backbone = inception_resnet(pretrained)
flat_shape = 1792
else:
raise ValueError('Unsupported backbone - `{}`, Use mobilenet, inception_resnetv1.'.format(backbone))
# 自适应平均池化层 参数(1, 1)表示输出的目标尺寸为1x1
self.avg = nn.AdaptiveAvgPool2d((1, 1))
# 正则化技术,用于减少深度神经网络中的过拟合问题,以一定的概率(通常在0.5到0.8之间)随机选择一些隐藏层神经元,并将其输出置为零
self.Dropout = nn.Dropout(1 - dropout_keep_prob) # 仅在训练时有用,防止模型的过拟合
# 全连接层作为模型的Bottleneck层 (flat_shape该层的输入维度大小、embedding_size该层的输出维度大小、bias是否使用偏置项)
# 将输入的特征向量从flat_shape维度变换为embedding_size维度的向量
self.Bottleneck = nn.Linear(flat_shape, embedding_size, bias=False)
# 进行标准化处理。使得每一层网络的输入分布保持相同的均值和方差,从而加速网络收敛并提高模型泛化能力
self.last_bn = nn.BatchNorm1d(embedding_size, eps=0.001, momentum=0.1, affine=True)
def forward(self, x, mode="predict"):
x = self.backbone(x)
x = self.avg(x)
# reshape,将其变为一个二维张量,其中第一维大小为原始张量的batch_size,第二维大小为剩余维度的乘积
x = x.view(x.size(0), -1)
x = self.Dropout(x)
x = self.Bottleneck(x)
x = self.last_bn(x)
x = F.normalize(x, p=2, dim=1) # l2标准化
return x
def forward_feature(self, x):
x = self.backbone(x)
x = self.avg(x)
x = x.view(x.size(0), -1)
x = self.Dropout(x)
x = self.Bottleneck(x)
before_normalize = self.last_bn(x)
x = F.normalize(before_normalize, p=2, dim=1)
return before_normalize, x
def forward_classifier(self, x):
x = self.classifier(x)
return x
导出onnx文件后,计划使用ONNX Runtime C++ API进行模型的部署、推理
部分代码如下:
#include <iostream>
#include <vector>
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
using namespace std;
using namespace Ort;
namespace imageHandle
{
class ImageHandler
{
public:
ImageHandler():
_memoryInfo(MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault))
{
Env env(ORT_LOGGING_LEVEL_ERROR, "ONNXRuntime")
// 创建 ONNX Runtime 会话选项
SessionOptions sessionOptions;
sessionOptions.SetIntraOpNumThreads(2); // 设置内部操作的线程数
sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); // 设置图优化级别
// 加载 ONNX 模型
const string modelPath = "/home/bjy/FaceRecSysOnnx/HandleServer/models/inception_resnerv1/inception_resnerv1.onnx";
_session = new Session(env, modelPath.c_str(), sessionOptions);
//...
}
};
}
出现类似下面的段错误(gdb调试core文件可见)
onnxruntime::logging::LoggingManager::Log(std::string const&, onnxruntime::logging::Capture const&) const (in /home/palermo/Programing_Workspace/TeseMestrado/na_high_evel/src/extra/onnxruntime/lib/libonnxruntime.so.1.5.2)
Segmentation Fault on session.Run() with custom model on c++ API · Issue #5630 · microsoft/onnxruntime · GitHubhttps://github.com/microsoft/onnxruntime/issues/5630
误以为env的作用仅仅是注册会话,导致编写时将其仅仅作为一个构造函数中的局部变量,实际上需维护到不再进行推理(参考上面的issue可知)
修改后代码:
#include <iostream>
#include <vector>
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
using namespace std;
using namespace Ort;
namespace imageHandle
{
class ImageHandler
{
public:
ImageHandler():
_env(Env(ORT_LOGGING_LEVEL_ERROR, "ONNXRuntime")),// 初始化 ONNX Runtime 环境
_memoryInfo(MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault))
{
// 创建 ONNX Runtime 会话选项
SessionOptions sessionOptions;
sessionOptions.SetIntraOpNumThreads(2); // 设置内部操作的线程数
sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); // 设置图优化级别
// 加载 ONNX 模型
const string modelPath = "/home/bjy/FaceRecSysOnnx/HandleServer/models/inception_resnerv1/inception_resnerv1.onnx";
_session = new Session(_env, modelPath.c_str(), sessionOptions);
//...
}
};
}