Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

设置单线程不生效 / API依赖onnxruntime / onnxruntime新版本头文件不匹配 #31

Closed
WN90 opened this issue Oct 21, 2024 · 3 comments

Comments

@WN90
Copy link
Contributor

WN90 commented Oct 21, 2024

三个问题

  1. cpu版本,设置单线程,但是仍然是多线程。
  2. c++ api 头文件依赖于 onnxruntime,如果封装一下对外头文件不带有onnxruntime,使用者不需要安装onnxruntime就可以用了。
  3. 代码中onnxruntime的头文件和onnxruntime最新版本不匹配,向前找了很多个版本都不匹配。

对于第一个问题,经过查看代码,发现在三处setNumThread函数中添加一行

     sessionOptions.SetInterOpNumThreads(numThread);
+    sessionOptions.SetIntraOpNumThreads(numThread);

就可以单线程执行。不知道这样修改和不合适。

对于第三个问题,猜测应该是onnxruntime版本的问题,似乎API已经变了很长时间了,是否应该以新版本为准?或者通过宏定义来区分。

-#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
+#include <onnxruntime_cxx_api.h>

对于第二个问题,我使用language server快速将OcrLite修改为OcrLiteImpl,然后将OcrLite.h和OcrLite.cpp修改为OcrLiteImpl.h和OcrLiteImpl.cpp,头文件防重复的宏定义也对应修改,再添加OcrLite.h和OcrLite.cpp,进行封装,经测试没有什么问题,使用的时候不依赖onnxruntime了。

#ifndef __OCR_LITE_H__
#define __OCR_LITE_H__

#include <string>
#include "OcrStruct.h"

class OcrLiteImpl;

class OcrLite{
public:
    OcrLite();

    ~OcrLite();

    void setNumThread(int numOfThread);

    void initLogger(bool isConsole, bool isPartImg, bool isResultImg);

    void enableResultTxt(const char *path, const char *imgName);

    void setGpuIndex(int gpuIndex);

    bool initModels(const std::string &detPath, const std::string &clsPath,
                    const std::string &recPath, const std::string &keysPath);

    void Logger(const char *format, ...);

    OcrResult detect(const char *path, const char *imgName,
                     int padding, int maxSideLen,
                     float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);

    OcrResult detect(const cv::Mat &mat,
                     int padding, int maxSideLen,
                     float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);

private:
    OcrLiteImpl* pImpl;
};

#endif //__OCR_LITE_H__
#include "OcrLite.h"
#include "OcrLiteImpl.h"

OcrLite::OcrLite() {
    pImpl = new OcrLiteImpl();
}

OcrLite::~OcrLite() {
    delete pImpl;
}

void OcrLite::setNumThread(int numOfThread) {
    pImpl->setNumThread(numOfThread);
}

void OcrLite::initLogger(bool isConsole, bool isPartImg, bool isResultImg) {
    pImpl->initLogger(isConsole, isPartImg, isResultImg);
}

void OcrLite::enableResultTxt(const char *path, const char *imgName) {
    pImpl->enableResultTxt(path, imgName);
}

void OcrLite::setGpuIndex(int gpuIndex) {
    pImpl->setGpuIndex(gpuIndex);
}

bool OcrLite::initModels(const std::string &detPath, const std::string &clsPath,
                         const std::string &recPath, const std::string &keysPath) {
    return pImpl->initModels(detPath, clsPath, recPath, keysPath);
}

void OcrLite::Logger(const char *format, ...) {
    if (!(pImpl->isOutputConsole || pImpl->isOutputResultTxt)) return;
    char *buffer = (char *) malloc(8192);
    va_list args;
    va_start(args, format);
    vsprintf(buffer, format, args);
    va_end(args);
    if (pImpl->isOutputConsole) printf("%s", buffer);
    if (pImpl->isOutputResultTxt) fprintf(pImpl->resultTxt, "%s", buffer);
    free(buffer);
}

OcrResult OcrLite::detect(const char *path, const char *imgName,
                          int padding, int maxSideLen,
                          float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) {
    return pImpl->detect(path, imgName, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
}

OcrResult OcrLite::detect(const cv::Mat &mat,
                          int padding, int maxSideLen,
                          float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) {
    return pImpl->detect(mat, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
}
@benjaminwan
Copy link
Member

benjaminwan commented Oct 21, 2024

代码合并了一些pr,但没有编译发布新版,暂时只能由使用者自行编译。

  1. 这个pr已经更改了线程配置代码:add:Added configuration parameters for the number of IntraOp threads #15
  2. 这只是个简单demo,没有做得很完善,欢迎贡献pr;
  3. 在Readme的更新说明里有onnxruntime版本:v1.2.2 对应onnxruntime 1.14.0,v1.2.3 对应onnxruntime 1.15.1;

想使用哪个版本的onnxruntime可以去Microsoft的官方仓库下载,或者我的另一个仓库:https://github.com/RapidAI/OnnxruntimeBuilder

@WN90
Copy link
Contributor Author

WN90 commented Oct 22, 2024

  1. OcrLite.h去除onnxruntime已经提了pr refactor: remove onnxruntime dependence in OcrLite.h #32
  2. 又测试了一下setNumThread使用两个线程的情况:
    1. 如果SetInterOpNumThreads和SetIntraOpNumThreads同时设置成1,cpu使用率100%。
    2. 然后我又分别设置SetInterOpNumThreads(1)和SetIntraOpNumThreads(2),cpu使用率250%以上。
    3. 反过来,前者1,后者2,使用率则为100%, 没办法达到预期200%
  3. 不清楚内部执行逻辑,但是既然onnx有inter和intra两个api,是否setNumThread也提供两个线程参数好一些, 如果保留一个参数的设置,可以将一个默认设置成1,配置的时候可选配置一个或两个,或者同时保留两个setNumThread函数,向前兼容。 Linux下如何绑定CPU核心运行 #16 这里面似乎也提到了cpu占用率非预期的问题。

@benjaminwan
Copy link
Member

分成两个涉及破坏性更新,不过这个项目已不再频繁开发,可能也不会有什么问题。

官方文档有提到最好让操作系统处理线程分配,所以原来没有把intra的配置也考虑进去。
https://onnxruntime.ai/docs/performance/tune-performance/threading.html#set-intra-op-thread-affinity
It is normally best to not set thread affinity and let the OS handle thread assignment for perf and power reasons.

但既然确实有用,那么综合来说,原来的inter仍然用setNumThread,而新的intra可以考虑另起一个方法去配置,未配置时由操作系统分配即可。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants