C++ でのニューラル ネットワーク用のオープンソース ライブラリの使用
導入
現代の AI は、Python、ノートブック、デモ環境を通じて企業に導入されることが多く、初めてモデルが機能するのを見たときの当然の興奮もあります。そのフェーズは現実的で、便利で、少し魔法的ですらあります。それは、好奇心が安く、反復が速いところです。しかし、実際の製品の寿命はデモで終わるわけではありません。顧客にサービスを提供し、バックエンドに適合し、工場のハードウェアで実行し、デスクトップ製品内で動作し、劣悪なネットワーク条件に耐えなければならないモデルは、もはや単なるモデルではありません。それはシステムのコンポーネントとなり、システムはエンジニアリングの成熟度が重要になり始める場所です。
それが C++ が部屋に戻ってくる瞬間です。エンジニアが過去について感傷的だからではなく、すべての AI の問題がネイティブの問題になるべきだからではなく、生産現場では、より高いレベルの実験では延期できる期間が限られている質問があるからです。プロセスに実際に必要なメモリ量はどれくらいですか?負荷がかかった状態での定常状態のレイテンシはどれくらいですか?起動時間は自動スケーリングに耐えることができますか?ランタイムは既存のネイティブ アプリケーション内に存在できますか?研究スタックを中心に製品全体を再構築せずに、同じ推論パスをサーバー、エッジボックス、オペレーターワークステーションに出荷することはできますか?
オープンソース ライブラリは、ベンダーのブラック ボックスに制御を明け渡すことなく、この移行を可能にします。これらは、安定したランタイム、テンソル抽象化、最適化されたカーネル、量子化された実行パス、ハードウェア対応バックエンド、そして最近の LLM 時代では驚くほど有能なローカル推論エンジンを提供します。しかし、図書館の多さが状況を混乱させる可能性もあります。エンジニアは、どのライブラリが最適であるかをよく尋ねますが、より良い質問は、どのライブラリが目の前の仕事に誠実であるかということです。
この記事では、そのより現実的な道をたどります。 AI の主要な C++ 関連ライブラリを、アイデンティティのバッジとしてではなく、長所、盲点、操作上の前提を備えたエンジニアリングの個性として見ていきます。最終的には、単に ONNX Runtime、LibTorch、oneDNN、OpenVINO、TensorFlow Lite、llama.cpp の名前を知ることが目標ではなくなります。目標は、それぞれがいつ役立つのか、いつ重くなりすぎるのか、どのように狭くなりすぎるのかを理解し、流行に流されずに選択する方法を理解することです。
AI システムが C++ に戻り続ける理由
AI の提供には、明確に名前を付ける価値のあるリズムがあります。一度理解すると、多くのアーキテクチャの選択肢が理解しやすくなるからです。まず最初に発見段階があります。研究者や製品エンジニアは、そのモデルで何ができるのか、どのようなデータが必要なのか、実際にどこに価値があるのかをまだ学んでいる最中です。その段階では、表現力が規律に勝ります。素早い実験、豊富な Python ツール、柔軟な研究フレームワークは、まさにチームが必要としているものです。
次に、あまり魅力的ではない第 2 段階が始まり、プロトタイプに義務が蓄積され始めます。サポート チームは障害を理解する必要があります。 SRE チームは、予測可能な起動とメモリの動作を望んでいます。財務部門は、サービス請求額が一時的な急増なのか、それとも永続的な漏れなのかを知りたいと考えています。組み込みの顧客から、モデルがオフラインで実行できるかどうか尋ねられました。セキュリティレビューでは、バイナリ内に正確に何が含まれているのか、またどの部分が監査できるのかが問われます。突然、モデルは研究成果物ではなくなり、実稼働環境の一員になります。
C++ を使用すると、エンジニアが具体的な質問に手を振るのではなく回答できるようになるため、その時点で C++ が戻ってきます。ネイティブ サービスは、割り当て戦略、スレッド プール、ABI 境界、パッケージ化、CPU 固有の最適化、および既存のパフォーマンス重視のサブシステムとの統合を制御できます。この制御は必ずしも必要というわけではありません。しかし、必要な場合には、レトリックで偽造することは非常に困難です。
ここでは便利な反例が役に立ちます。チームが 1 時間に 1 回実行される、負荷の軽い内部ドキュメント分類器を構築している場合、最も抵抗の少ない方法は、安定したサービス提供フレームワークとネイティブ コードがほとんどない Python サービスである可能性があります。それは何も恥ずかしいことではありません。一方で、同じチームがレイテンシの影響を受けやすい C++ デスクトップ アプリケーション内に推論を埋め込んだり、リソースが限られたエッジ デバイスに送信したり、モデルの実行をホット バックエンド パスに直接挿入したりしている場合、ランタイム言語が問題ではないふりをすることはすぐにコストが高くなります。言い換えれば、C++ は AI のすべての問題に対する答えではありませんが、システム自体が問題となる場合には常に最も深刻な答えの 1 つであることに変わりはありません。
エンジニアリングの個性としての図書館
このエコシステムで迷子になる最も簡単な方法は、すべてのライブラリを同じ仕事を求めて競合しているかのように扱うことです。そうではありません。トレーニング指向のフレームワーク、ポータブル推論ランタイム、カーネル ライブラリ、ローカル LLM エンジンはすべて、さまざまな問題を解決します。これらを AI ライブラリと呼ばれる 1 つのカテゴリに分類すると、システム設計ではなくブランドの馴染みに基づいて選択を行うことになります。
ONNX ランタイムは、多くの運用環境において、最も規律があり、煩雑さが少ない選択肢です。これは、モデルを安定した形式にエクスポートし、実行に重点を置いたランタイムを通じてロードし、アプリケーションがシステムの残りの部分を所有できるようにするという明確な約束に基づいて構築されています。それは簡単に聞こえますが、シンプルさこそが強力な理由です。研究フェーズがすでに他の場所で行われており、残っているのは推論を繰り返し、移植可能に、予測可能な動作動作で提供するという地味な作業だけである場合、ONNX ランタイムは多くの場合正しい答えになります。画像を受け取り、テンソルを正規化し、既知のグラフを実行し、結果を既存の C++ サービスに返すコンピューター ビジョン バックエンドは、理想的な ONNX ランタイム ストーリーです。適合性が低い製品は、その核となる価値が、動的なトレーニング時の動作、アプリケーション内での頻繁なグラフ操作、またはエクスポートを脆弱にする絶えず変化するカスタム演算子のセットに依存する製品です。このような場合、最初はきれいに見えた実行時の境界が摩擦の原因になる可能性があります。
LibTorch は性質が異なります。これは主に軽量の実行境界ではありません。これは、完全な深層学習フレームワークの C++ の顔です。それにより重くなりますが、より表現力豊かになります。ネイティブ アプリケーションが本当にテンソル演算を所有し、モデルを構築し、トレーニングのような操作を実行する必要がある場合、または開発と運用全体にわたって PyTorch セマンティクスに近づき続ける必要がある場合、LibTorch は ONNX ランタイムよりも魅力的になります。製品にランタイムだけでなくフレームワークが本当に必要な場合、それを選択するのはある程度の誠実さがあります。反例も同様に重要です。チームは、権威ある、または将来性があると感じられるため、単純な静的推論に LibTorch を採用することがあります。その後、必要なワークロードよりもはるかに大きな概念的および運用面をインポートしたことに気づきました。安定したモデル グラフをロードすることだけが必要な小規模な推論サービスでは、パッケージのサイズ、複雑さ、デバッグの労力という点で、その決定の代価が支払われる可能性があります。
oneDNN と OpenVINO はメタルに近い環境にあり、パフォーマンスをより重視する考え方に報います。 oneDNN は、完全な製品ストーリーが必要なために通常使用するライブラリではありません。これは、CPU カーネル、メモリ形式、およびオペレータレベルの効率が直接の注目に値するほど重要になるときに、重宝するライブラリです。多くのチームは、より高いレベルのランタイムを通じて間接的にこれを使用していますが、これは多くの場合賢明です。一方、OpenVINO はより戦略的な位置にあります。これは、下位レベルの詳細をすべて手動で管理したくない、インテル指向の導入、グラフの最適化、ハードウェアを意識した実行に関心を持つチームを支援します。実際には、ビジネス上の問題が単に「モデルを実行する」だけではなく、「実際に購入、導入、保守できるハードウェア上で効率的にモデルを実行する」ことになったときに、これらのツールが重要になり始めます。この区別は会議では小さなものに見えますが、予算では非常に大きくなります。
TensorFlow Lite は、まったく別の気質を表します。自粛の声です。エッジ デバイス、モバイル ターゲット、およびリソースに制約のあるシステムでは、完全性は適合性よりも価値が低いことがよくあります。エンジニアはそこに壮大なフレームワークを必要としません。メモリ、パッケージ サイズ、エネルギー使用量、起動時間などの厳しい制約をロードし、実行し、その範囲内に留まるモデルが必要です。 TensorFlow Lite は、デプロイメント ターゲット自体がアーキテクチャを形成する主な力である場合に意味を成します。反例もよくあります。チームは、効率的だと思われるエッジ ランタイムから始めて、それを徐々に拡張して、より広範なサーバー プラットフォームや、サポートするために構築されたものよりも動的なニーズを伴うワークフローに拡張します。エッジでの効率が他の場所で自動的に快適になるわけではありません。
次に、llama.cpp があります。これは、局所推論の感情マップを変更したため、特に注目に値します。 llama.cpp や同様のプロジェクトが主流になる前、多くのエンジニアは、ローカルの大規模言語モデルの提供は研究用のおもちゃかエンタープライズ アプライアンスにとどまると考えていました。 llama.cpp は、さらに興味深いことを実証しました。積極的な量子化、慎重なカーネル作業、規律あるエンジニアリングにより、最新の LLM が通常のシステム内のローカル ネイティブ コンポーネントになる可能性があります。その洞察は、1 つのプロジェクトを超えて重要です。これは、ネイティブ実行、モデル圧縮、および実際のデプロイメントが、集中型の説明が示唆するよりもはるかに速く進む可能性があることを現場全体に思い出させました。しかし、llama.cpp にも自然な境界があります。これは、ジョブがサポートされている変圧器モデルをローカルかつ効率的に実行している場合に優れています。これはディープラーニング エコシステム全体の一般的な代替品ではないため、チームがそれを 1 つになるように要求すると問題が発生します。
誇大宣伝に惑わされずに選ぶ方法
これらのライブラリの中から選択する最も信頼できる方法は、製品から始めて、後でツールに名前を付けることです。まず、アプリケーションが実際に何を所有し、何を単に消費しているのかを考えることから始めます。システムが主に安定したモデルを使用し、移植性の高い制限された推論を必要とする場合、多くの場合、ONNX ランタイムが最も穏やかな答えになります。システム自体がテンソル、モジュール、フレームワーク セマンティクスの言語で話さなければならない場合、LibTorch について議論する価値があります。 CPU 効率、グラフの最適化、または Intel を多用する展開が難しい部分である場合は、oneDNN と OpenVINO が中心に近づきます。ターゲットが小さい、オフライン、バッテリーに敏感、または埋め込まれている場合、TensorFlow Lite はより自然になります。製品がネイティブ環境でローカルの量子化言語モデルを実行することを明示的に目的としている場合は、llama.cpp が早期に検討の対象になります。
2 番目の質問も同様に重要です。エンジニアリングの負担は実際にどこで支払われるのでしょうか?チームは、ベンチマークの見出しに従ってライブラリを選択した後、本当の悩みは別のところにあることに気づくことがよくあります。エクスポートが不安定だったり、前処理が面倒だったり、展開パッケージが脆かったりする場合には、驚異的なスループット数値を持つランタイムでも不適切な可能性があります。モデル作成者とシステム保守者の間に明確な境界が作成されるのであれば、実行時間が多少遅くても、ビジネス上の選択としては依然として優れている可能性があります。複数の AI 製品を出荷したエンジニアは、この教訓を深く学びます。最良のライブラリとは、常にベンチマーク チャートで優勝するものではなく、午前 2 時にシステム全体の推論を容易にするものです。
ここで反例が健全になります。ネイティブ ドキュメント分析サービスを構築するチームを考えてみましょう。ファッショナブルな選択は、将来性があると思われる、利用可能な最も重いフレームワークに手を伸ばすことかもしれません。ただし、モデルが静的で、前処理パイプラインが単純で、実際に必要なのは既存の C++ サービス内での安定した推論である場合、ONNX ランタイムによる長期的な影響は少なくなる可能性があります。次に、逆のことを考えてみましょう。チームは、カスタム tensor フロー、頻繁なアーキテクチャ変更、および PyTorch ベースのトレーニング ロジックとの密結合を使用したネイティブ実験を行っています。 「本番環境に対応している」と思われるからといって、すべてを ONNX に強制的に通すと、誰も心から楽しんでいない脆弱なエクスポート中心のワークフローが作成される可能性があります。どの場合でも間違いは同じです。チームはワークロードを選択する前に ID を選択しました。
優れた統合とは実際どのようなものなのか
成熟した統合ワークフローは、ライブラリではなくデータ コントラクトから始まります。ランタイムについて議論する前に、アプリケーションがモデルに何を与えるか、モデルがアプリケーションに何を返すかを決めてください。テンソル形状、dtype、正規化ルール、トークン化パス、パディング動作、バッチ処理の仮定、およびエラー条件に名前を付けます。これはほとんど官僚的に聞こえますが、これは多くの導入成功の静かな源です。システムが失敗するのは、ランタイムが間違っているだけではなく、その周囲の境界が曖昧であることが原因です。
データ コントラクトが安定すると、エクスポートやモデルのパッケージ化の検証がはるかに簡単になります。チームは、代表的な入力の下で研究パスと生産パスの間の出力を比較し、許容差を測定し、忠実度がドリフトしている場所を検出できます。ここでエンジニアは、エレガントなアーキテクチャが現実に耐えられるかどうかを発見します。エクスポートされたグラフには問題がなく、前処理の不一致だけが問題である場合もあります。ランタイムが完璧であっても、実際の問題はサービス内の他の場所でのスレッドのオーバーサブスクリプションである場合があります。場合によっては、小規模であるはずのモデルが、実際の同時実行によるメモリ負荷に耐えられないことがあります。これらの発見はどれも役に立ちます。システムが見え始めたということです。
その後、ベンチマークとプロファイリングが行われますが、ここでも同じ古いルールが適用されます。つまり、賢いと感じていたおもちゃではなく、出荷する予定のシステムを測定することです。現実的なリクエストの形状、バッチ サイズ、入力の変動性、およびハードウェア条件の下でモデルのベンチマークを実行します。プロファイルの前処理と後処理も同様です。これは、多くのチームが無意識のうちにモデルのコアのみをベンチマークし、顧客がパス全体に対して料金を支払うことを忘れているためです。実稼働 AI では、60 ミリ秒の回避可能な接着剤で囲まれた 10 ミリ秒のグラフは、依然として 70 ミリ秒の機能です。
最後に、展開を再現可能にします。ネイティブ AI スタックは規律に報酬を与えます。バージョンを固定し、コンパイラーとランタイムの前提条件を文書化して、どの実行プロバイダーまたは CPU 機能が必要かを決定し、サポートされる構成の狭いセットを維持します。チームメイトが考古学なしで同じ推論パスを別のマシンで再現できない場合、デモがどれほど印象的だったとしても、スタックは準備ができていません。優れた C++ AI エンジニアリングは速度だけではありません。速度を理解できる程度にシステムを落ち着かせることが重要です。
繰り返される間違い
最もよくある間違いは、研究の真実と生産の真実を取り違えることです。ノートブックでは優れているように見えるモデルでも、実際の同時実行下でエクスポート、量子化、埋め込み、観察、実行すると扱いにくくなる可能性があります。だからといってモデルが悪かったわけではありません。これは、システムが実験よりも大きかったことを意味します。 2 番目に繰り返される間違いは、前処理と後処理が二の次であるかのように振る舞うことです。実際の製品では、作業の半分で済むことがよくあります。画像のサイズ変更ポリシー、トークナイザーの動作、特徴の正規化、キャリブレーションしきい値、および出力デコードによるすべての形状の正確性と遅延は、コア ランタイムと同様に確実です。
3 番目の間違いは、フレームワークが現代的または包括的であると感じるために、フレームワークに過度にコミットすることです。エンジニアは、決して到来しないニーズを予測して、可能な限り最大のツールを選択することがあります。製品は、使用しない機能に対して料金を支払います。逆の間違いも存在します。純度の名の下に最も軽いランタイムを選択し、その後、動的な動作、カスタム操作、またはフレームワークレベルのセマンティクスが結局はオプションではなかったことが判明するということです。知恵とは、実際に説明できる力に対してのみ料金を支払うことにあります。
さらに微妙な態度の失敗もあります。一部のチームは、ライブラリの選択がエンジニアリングのストーリー全体を解決するかのように扱っています。そうではありません。良い結果は、出力の検証、ホット パスの測定、回避可能なコピーの削除、起動時の負荷の軽減、パッケージの簡素化、実行時の境界の読みやすさの維持など、地味な作業の繰り返しから得られます。オープンソース ライブラリにより、この作業が可能になります。彼らは私たちに代わってそれを実行するわけではありません。
覚えておく価値のある小さな導入ストーリー
Python ビジョンのプロトタイプから始まるチームを想像してください。このデモは社内のサポートを得るのに十分な強力なものであり、すぐに会話は、イメージの取り込み、ルールの評価、レポートをすでに処理している既存の C++ サービスとの統合に移ります。チームにはいくつかの誘惑があります。 1 つは、短期的には簡単なので、モデルを別の Python サービスの背後に永久に保持することです。もう 1 つは、深刻に聞こえるため、すべてをすぐに重量のあるネイティブ フレームワークに移行することです。 3 つ目は、入力コントラクトさえ安定させる前に、アーキテクチャについて何週間も議論することです。
より成熟した道は静かです。まず、チームは前処理と出力セマンティクスを慎重に定義します。次に、代表的な画像のエクスポートの忠実度をテストします。問題は静的な推論であり、フレームワーク主導の実験ではないため、ONNX ランタイムを選択します。その後、ハードウェア制約がより厳しいエッジ バリアントについては、TensorFlow Lite またはより積極的に最適化されたランタイム パスがその製品ブランチにとって意味があるかどうかを評価します。数か月後、同社がローカル アシスタント機能を追加した場合、llama.cpp もアーキテクチャに参入する可能性があります。これは、1 つのライブラリが議論全体に勝ったからではなく、各ツールがシステムの別の隅にその場所を獲得したからです。
これが、これらすべてのライブラリの背後にある深い教訓です。本格的な AI エンジニアリングが純粋さに報われることはほとんどありません。それはフィット感を与えます。最高のオープンソース ライブラリとは、最も多くの支持を得ているライブラリではありません。これは、システムの残りの部分に無理を強いることなく、モデルを実際のシステムの一部にできるようにするものです。
ハンズオン ラボ: 小さな ONNX ランタイム CLI を構築する
理論は組み立てられると説得力が増します。
C++ で最小の有用なネイティブ推論プログラムを構築してみましょう。目標はモデルをトレーニングすることではありません。目標は、ネイティブのランタイム境界がどのようなものかを自分の手で感じることです。
この演習には次のものが必要です。
- C++17 コンパイラ
- CMake
- 公式リリースからの事前構築済み ONNX ランタイム パッケージ
- 入力が平坦な浮動小数点テンソルである任意の小さな
.onnxモデル
プロジェクトのレイアウト
tiny-ort/
CMakeLists.txt
main.cpp
third_party/
onnxruntime/
model.onnx
__コード_0__
cmake_minimum_required(VERSION 3.16)
project(tiny_ort LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(ORT_ROOT "${CMAKE_SOURCE_DIR}/third_party/onnxruntime")
add_executable(tiny_ort main.cpp)
target_include_directories(tiny_ort PRIVATE "${ORT_ROOT}/include")
if (WIN32)
target_link_directories(tiny_ort PRIVATE "${ORT_ROOT}/lib")
target_link_libraries(tiny_ort PRIVATE onnxruntime)
else()
target_link_directories(tiny_ort PRIVATE "${ORT_ROOT}/lib")
target_link_libraries(tiny_ort PRIVATE onnxruntime)
endif()
__コード_0__
#include <onnxruntime_cxx_api.h>
#include <array>
#include <iostream>
#include <numeric>
#include <vector>
int main() {
Ort::Env env{ORT_LOGGING_LEVEL_WARNING, "tiny-ort"};
Ort::SessionOptions opts;
opts.SetIntraOpNumThreads(1);
opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
const ORTCHAR_T* model_path = ORT_TSTR("model.onnx");
Ort::Session session{env, model_path, opts};
std::vector<int64_t> shape{1, 4};
std::vector<float> input{0.25f, 0.50f, 0.75f, 1.0f};
auto mem_info = Ort::MemoryInfo::CreateCpu(
OrtArenaAllocator,
OrtMemTypeDefault
);
Ort::Value tensor = Ort::Value::CreateTensor<float>(
mem_info,
input.data(),
input.size(),
shape.data(),
shape.size()
);
const char* input_names[] = {"input"};
const char* output_names[] = {"output"};
auto outputs = session.Run(
Ort::RunOptions{nullptr},
input_names,
&tensor,
1,
output_names,
1
);
float* out = outputs[0].GetTensorMutableData<float>();
auto out_shape = outputs[0].GetTensorTypeAndShapeInfo().GetShape();
auto out_count = std::accumulate(
out_shape.begin(),
out_shape.end(),
int64_t{1},
std::multiplies<int64_t>{}
);
std::cout << "Output values:\n";
for (int64_t i = 0; i < out_count; ++i) {
std::cout << " [" << i << "] = " << out[i] << "\n";
}
return 0;
}
建てる
Linux または macOS の場合:
cmake -S . -B build
cmake --build build -j
./build/tiny_ort
MSVC を使用する Windows の場合:
cmake -S . -B build
cmake --build build --config Release
.\build\Release\tiny_ort.exe
これが教えてくれること
この小さなプロジェクトでは、すでに次のようないくつかの生産上の現実に直面する必要があります。
- ランタイムが存在する場所
- ネイティブ依存関係がどのようにパッケージ化されるか
- テンソルの名前と形状は実際には何ですか
- ネイティブ推論境界における明示的なメモリ処理の感触
まさにそれがポイントです。ライブラリはマーケティング用語ではなくなり、エンジニアリング上の選択肢になります。
愛好家向けのテストタスク
この記事を週末のラボにしたい場合は、次のステップが役立ちます。
- ハードコードされた入力ベクトルを、小さなテキスト ファイルまたはバイナリ ファイルからロードされた値に置き換えます。
- 入力および出力のテンソル形状を想定するのではなく、動的に出力します。
session.Runの周囲に単純なレイテンシー測定を追加し、1、2、および4の演算内スレッドを比較します。- 同様のおもちゃ推論アプリで ONNX ランタイムを LibTorch に交換し、何が簡単になったのか、何が重くなったのかを書き留めます。
- Python から小さなモデルをエクスポートし、それをこの C++ プログラムにロードし、前処理の違いによって結果が暗黙的に変更されないことを確認します。
これら 5 つのタスクを正直に実行すれば、フレームワークの名前を 1 時間暗唱できる多くの人よりも AI の導入について理解できるようになります。
まとめ
C++ 用のオープンソース ニューラル ネットワーク ライブラリは、一度のパレードで行進するわけではありません。これらはさまざまなエンジニアリングのニーズから生まれたものであり、その起源を尊重する場合に最も有用であり続けます。 ONNX ランタイムは、問題を絞り込み、運用チームに安定した推論境界を与えるため、強力です。 LibTorch は、ネイティブ アプリケーションが単に凍結されたグラフを使用するのではなく、本当にテンソルとモジュールで考える必要がある場合に役立ちます。 oneDNN と OpenVINO は、低レベルの効率性と特定のハードウェア ファミリへの展開が二次的な問題ではなくなるときに重要になります。 TensorFlow Lite は、デバイス自体がハード制約である場合に威力を発揮します。 llama.cpp が重要なのは、注意深くネイティブ エンジニアリングを行うことで、現代の言語モデルを遠隔サービスではなく実用的なローカル コンポーネントに変えることができることを公に証明したからです。
したがって、最良の選択が最もファッショナブルなものであることはめったにありません。システム全体を穏やかにするものです。優れたランタイムとは、神話にとらわれずにチームが理解し、ベンチマーク、プロファイル、パッケージ化、テスト、運用できるランタイムのことです。エンジニアがそこから選択すると、オープンソース AI は、フレームワークのわかりにくい動物園のように見えるのをやめ、本当の姿、つまり本格的なネイティブ製品をサポートするのに十分な豊富なツールボックスのように見え始めます。
参考文献
- ONNX ランタイム C/C++ API: https://onnxruntime.ai/docs/api/c/index.html
- ONNX 公式プロジェクト: https://onnx.ai/
- PyTorch C++ フロントエンドのドキュメント: https://docs.pytorch.org/cppdocs/frontend.html
- oneDNN 公式ドキュメント: https://uxlfoundation.github.io/oneDNN/
- OpenVINO ドキュメント: https://docs.openvino.ai/
- LiteRT / TensorFlow Lite C++ API ドキュメント: https://ai.google.dev/edge/litert/api_docs/cc
- llama.cpp リポジトリ: https://github.com/ggml-org/llama.cpp
- ONNX ランタイム GitHub リポジトリ: https://github.com/microsoft/onnxruntime
- PyTorch リポジトリ: https://github.com/pytorch/pytorch