Edge AI & Cloud/On-Device AI & Edge Hardware

ONNX Runtime Mobile 도입 가이드: C++ API 기반 iOS 및 Android 크로스 플랫폼 추론 구현

임베디드 친구 2026. 8. 17. 14:52
반응형

1. ONNX Runtime Mobile C++ API 기반 크로스 플랫폼 On-Device AI 구축 배경

모바일 및 엣지 디바이스 환경에서 딥러닝 모델을 구동할 때 OS별(Android, iOS)로 추론 엔지니어링을 따로 구현하는 방식은 파편화와 유지보수 비용 증가를 초래합니다. Android의 NNAPI/TFLite와 iOS의 CoreML/MPSgraph 프레임워크를 각각 다루는 방식은 최적화 로직과 후처리 코드가 중복되는 문제가 발생합니다.

ONNX Runtime Mobile은 단일 C++ API 레이어를 통해 이러한 파편화 이슈를 해결합니다. 플랫폼 종속성을 제거하고 공통 C++ 엔진을 구축함으로써 iOS(CoreML execution provider)와 Android(NNAPI/NNAPI EP)의 하드웨어 가속기(NPU, GPU)를 동일한 코드베이스로 제어할 수 있습니다. 본 가이드는 ONNX Runtime Mobile C++ API를 활용하여 모바일 디바이스에서 고성능 크로스 플랫폼 추론 파이프라인을 구축하는 가이드를 제공합니다.

2. ONNX Runtime Mobile 핵심 기술 요약 (Technical Summary)

  • Cross-Platform C++ Core Engine: Ort::Env 및 Ort::Session C++ API를 활용하여 Android와 iOS에서 동일한 딥러닝 추론 파이프라인을 동작시킵니다.
  • Hardware Acceleration Provider Integration: Android 환경에서는 OrtSessionOptionsAppendExecutionProvider_Nnapi를 사용하고, iOS 환경에서는 OrtSessionOptionsAppendExecutionProvider_CoreML을 통해 NPU/GPU 가속을 활성화합니다.
  • ORT Format Optimization: 메모리 사용량을 절감하기 위해 .onnx 모델을 모바일 최적화 포맷인 .ort 파일로 변환하여 런타임 이니셜라이제이션 성능을 극대화합니다.

3. ONNX Runtime Mobile C++ API 상세 분석 및 모바일 연동 구현

ONNX Runtime Mobile 실행 파이프라인 아키텍처

ONNX Runtime Mobile의 C++ 파이프라인은 세션 환경 설정(Ort::Env), 옵션 초기화 및 Execution Provider 추가(Ort::SessionOptions), 모델 로딩(Ort::Session), 그리고 텐서 입력/출력 매핑(Ort::Value)의 순서로 진행됩니다.

[ONNX / ORT Model File] 
          │
          ▼
   Ort::Env Engine ───► Ort::SessionOptions (EP Configuration: NNAPI / CoreML)
          │
          ▼
     Ort::Session ───► Allocator / Memory Info Setup
          │
          ▼
    Ort::Value ───► Session.Run() ───► Output Tensors

Execution Provider(EP) 백엔드 비교 및 모바일 최적화 특징

평가 항목 (Feature) Android (NNAPI Execution Provider) iOS (CoreML Execution Provider) CPU Fallback
하드웨어 가속기 NPU / DSP / GPU (Qualcomm Hexagon, Mali, Adreno) Apple Neural Engine (ANE) / Apple GPU CPU (XNNPACK / ARM NEON)
API 함수 OrtSessionOptionsAppendExecutionProvider_Nnapi OrtSessionOptionsAppendExecutionProvider_CoreML 기본 적용 (Default)
추론 속도 (Latency) 매우 빠름 (HW 드라이버 지원 시) 매우 빠름 보통
메모리 오버헤드 중간 (Driver 컴파일 비용 발생) 작음 최소

ONNX Runtime C++ API 추론 엔진 파이프라인 소스코드 분석

다음 예제는 Android NDK Native Layer 및 iOS C++ Framework 레벨에서 공통으로 실행 가능한 C++ 추론 파이프라인 구현 코드입니다.

#include <iostream>
#include <vector>
#include <onnxruntime_cxx_api.h>

// Include Execution Provider headers based on platform
#if defined(__ANDROID__)
#include <onnxruntime_c_api.h>
#elif defined(__APPLE__)
#include <coreml_provider_factory.h>
#endif

class OnnxInferenceEngine {
private:
    Ort::Env env;
    Ort::SessionOptions sessionOptions;
    Ort::Session* session = nullptr;
    Ort::MemoryInfo memoryInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);

public:
    OnnxInferenceEngine() : env(ORT_LOGGING_LEVEL_WARNING, "MobileInference") {}

    ~OnnxInferenceEngine() {
        if (session) {
            delete session;
        }
    }

    void InitializeEngine(const char* modelPath) {
        // Enable basic optimizations
        sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);

#if defined(__ANDROID__)
        // Append NNAPI Execution Provider for Android NPU acceleration
        uint32_t nnapi_flags = 0;
        OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_Nnapi(sessionOptions, nnapi_flags);
        if (status != nullptr) {
            std::cerr << "Failed to append NNAPI Execution Provider." << std::endl;
        }
#elif defined(__APPLE__)
        // Append CoreML Execution Provider for iOS ANE acceleration
        uint32_t coreml_flags = 0;
        OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CoreML(sessionOptions, coreml_flags);
        if (status != nullptr) {
            std::cerr << "Failed to append CoreML Execution Provider." << std::endl;
        }
#endif

        // Create Ort::Session
        session = new Ort::Session(env, modelPath, sessionOptions);
    }

    std::vector<float> RunInference(const std::vector<float>& inputData, const std::vector<int64_t>& inputShape) {
        const char* inputNames[] = {"input"};
        const char* outputNames[] = {"output"};

        // Create Input Tensor from vector
        size_t inputTensorSize = inputData.size();
        Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
            memoryInfo,
            const_cast<float*>(inputData.data()),
            inputTensorSize,
            inputShape.data(),
            inputShape.size()
        );

        // Execute Model Inference
        auto outputTensors = session->Run(
            Ort::RunOptions{nullptr},
            inputNames,
            &inputTensor,
            1,
            outputNames,
            1
        );

        // Extract Output Tensor Data
        float* floatArray = outputTensors[0].GetTensorMutableData<float>();
        size_t outputSize = outputTensors[0].GetTensorTypeAndShapeInfo().GetElementCount();

        return std::vector<float>(floatArray, floatArray + outputSize);
    }
};

4. ONNX Runtime Mobile 실무 연동 및 최적화 개발 팁

  • ORT Format Model Conversion: 모바일 빌드에서는 바이너리 용량을 줄이고 로딩 속도를 올리기 위해 기존 .onnx 포맷을 .ort 포맷으로 변환해야 합니다. Python 환경에서 onnxruntime.tools.convert_onnx_models_to_ort CLI 명령어를 수행하여 경량화 포맷으로 변환 후 연동하세요.
  • CPU Fallback 옵션 구성: 하드웨어 가속기(NNAPI/CoreML)에서 지원하지 않는 커스텀 연산자(Custom Operator)가 모델에 포함된 경우 에러가 발생할 수 있습니다. EP 초기화 함수 실패 시 즉시 CPU 백엔드로 롤백되는 예외 처리 로직을 구현하세요.
  • Inference Memory Pool Reuse: Ort::Value 생성 시 매 추론마다 메모리를 동적 할당하지 않고, 사전 할당된 버퍼(Pre-allocated Memory)를 사용하도록 처리하여 GC(Garbage Collection) 및 Heap overhead를 제거하세요.

5. ONNX Runtime Mobile 적용 시 흔히 하는 실수 및 예외 해결법

  • Tensor Shape Mismatch (ORT_INVALID_ARGUMENT):
    • 에러 예시: OnnxRuntimeError: Invalid rank for input
    • 원인: C++ 백엔드로 넘겨주는 inputShape 벡터의 차원 값이나 요소 개수가 모델 초기 설정과 일치하지 않는 경우 발생합니다.
    • 해결법: session->GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape() API를 사용하여 모델이 기대하는 Shape 정보를 명확히 검증 후 텐서를 입력하세요.
  • Execution Provider 가속 실패 및 Crash:
    • 에러 예시: NNAPI EP driver missing or invalid node
    • 원인: Android OS 버전이 낮거나 NPU 드라이버 지원 범위 밖에 있는 딥러닝 레이어가 모델에 존재할 때 발생합니다.
    • 해결법: OrtSessionOptionsAppendExecutionProvider_Nnapi 실행 후 반환되는 OrtStatus*를 검사하고 status != nullptr인 경우 해당 EP 세션을 해제하고 기본 CPU 세션으로 세이프티 가드를 작성하세요.
  • iOS Bitcode 및 Framework Symbol Missing:
    • 원인: Xcode 빌드 환경에서 ONNX Runtime Static C++ Framework 링크 누락으로 인해 C++ 내 static symbol을 참조하지 못하는 현상입니다.
    • 해결법: Xcode Build Settings에서 Other Linker Flags 항목에 -ObjC 및 -all_load 옵션을 지정하고 ONNX Runtime C++ Header Path가 정상인지 확인하세요.

6. ONNX Runtime Mobile C++ 연동 결론

ONNX Runtime Mobile의 C++ API를 활용하면 iOS와 Android 디바이스 모두에서 동등한 성능과 높은 일관성을 가진 On-Device AI 추론 파이프라인을 구축할 수 있습니다. NNAPI 및 CoreML Execution Provider를 효율적으로 활성화하고 .ort 최적화 포맷을 적용하여 모바일 엣지 환경에서 실시간 AI 서비스를 성공적으로 구현하기 바랍니다.

반응형