Python学習モデルをC++で爆速推論！ONNX形式連携チュートリアル【macOS対応・IRバージョン対応済】

# ✅ 概要

ONNX（Open Neural Network Exchange）は、さまざまな機械学習フレームワークのモデルを**共通フォーマットで保存・再利用できる仕組み**です。
本記事では以下をステップごとに実現します：

* Pythonで機械学習モデルを学習・ONNX形式で出力（**IRバージョン対応済み**）
* macOS上でC++ + ONNX Runtimeを使い**爆速で推論実行**
* REST不要・Python不要・エッジ端末にも展開可能な構成


## 🔧 STEP1：Pythonでモデル学習 → ONNX形式に変換

### ライブラリインストール

```bash
pip install scikit-learn skl2onnx onnx
```

### 学習＆ONNX出力コード（※ IRバージョン対応）

```python
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

# データ準備＆学習
X, y = load_iris(return_X_y=True)
model = RandomForestClassifier()
model.fit(X, y)

# ONNX変換（互換性を保つために opset 11 を指定）
initial_type = [('input', FloatTensorType([None, 4]))]
onnx_model = convert_sklearn(model, initial_types=initial_type, target_opset=11)

# 保存
with open("rf_model.onnx", "wb") as f:
    f.write(onnx_model.SerializeToString())
```

## 🧰 STEP2：ONNX Runtime (macOS用) を導入

### 最新安定版（v1.17.1）を取得

```bash
curl -L -o onnxruntime-osx-universal2.tgz \
  https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-osx-universal2-1.17.1.tgz

tar -xvzf onnxruntime-osx-universal2.tgz
```

展開後のディレクトリは `onnxruntime-osx-universal2-1.17.1` です。

## ⚙️ STEP3：C++でONNXモデルを実行

### C++コード（main.cpp）

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

int main() {
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ONNXExample");
    Ort::SessionOptions session_options;
    session_options.SetIntraOpNumThreads(1);

    // モデル読み込み
    const char* model_path = "rf_model.onnx";
    Ort::Session session(env, model_path, session_options);

    Ort::AllocatorWithDefaultOptions allocator;
    Ort::AllocatedStringPtr input_name = session.GetInputNameAllocated(0, allocator);
    Ort::AllocatedStringPtr output_name = session.GetOutputNameAllocated(0, allocator);

    std::vector<float> input_data = {5.1f, 3.5f, 1.4f, 0.2f};
    std::vector<int64_t> input_shape = {1, 4};

    Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
    Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
        memory_info, input_data.data(), input_data.size(),
        input_shape.data(), input_shape.size()
    );

    std::vector<const char*> input_names = {input_name.get()};
    std::vector<const char*> output_names = {output_name.get()};
    auto output_tensors = session.Run(Ort::RunOptions{nullptr},
                                      input_names.data(), &input_tensor, 1,
                                      output_names.data(), 1);

    float* result = output_tensors.front().GetTensorMutableData<float>();
    std::cout << "予測クラスID: " << static_cast<int>(result[0]) << std::endl;

    return 0;
}
```
## 🔨 STEP4：ビルド＆実行（macOS）

### コンパイル

```bash
g++ -std=c++17 main.cpp -o onnx_infer \
  -I./onnxruntime-osx-universal2-1.17.1/include \
  -L./onnxruntime-osx-universal2-1.17.1/lib -lonnxruntime
```

### 実行（ライブラリパス指定）

```bash
export DYLD_LIBRARY_PATH=./onnxruntime-osx-universal2-1.17.1/lib:$DYLD_LIBRARY_PATH
./onnx_infer
```


### 実行結果（例）

```
予測クラスID: 0
```

`Iris-setosa` に対応する予測結果が表示されます（モデルによって異なります）。


# 📌 トラブル回避のポイント

| 問題                                 | 解決策                                        |
| ---------------------------------- | ------------------------------------------ |
| `onnxruntime_cxx_api.h` not found  | `-I` オプションで `include` を正しく指定               |
| `Unsupported model IR version: 10` | Pythonで `target_opset=11` を指定してONNX変換      |
| `dyld: Library not loaded:`        | `export DYLD_LIBRARY_PATH=...` を忘れずに実行前に指定 |

# ✅ まとめ

| ステップ   | 内容                 |
| ------ | ------------------ |
| Python | 学習＋ONNX変換（互換性に配慮）  |
| ONNX形式 | 軽量・高互換なモデル交換形式     |
| C++    | 高速・ネイティブ・REST不要な推論 |

この構成により、macOSやエッジ環境でも超高速かつ軽量なAI推論が可能になります。

# 参考資料
https://qiita.com/studio_haneya/items/be9bc7c56af44b7c1e0a