発表の概要:IntelとAMDが合意したoneDNNへのx86最適化集約
IntelとAMDは2026年10月20日、PyTorchにおけるx86 CPU推論の最適化をoneDNNに集約し、oneDNNをx86向け最適化の共通オープンソースライブラリーとする協業を発表しました[1]。この合意に基づき、AMDは自社のCPU向け推論最適化ライブラリであるZenDNNの最適化をoneDNNへ統合します[2, 3, 4]。
この発表に先立ち、oneDNNのリポジトリでは統合に向けた初回実装が進められていました。2026年7月16日、oneDNNのmainブランチにプルリクエストPR #5511がマージされました[5, 6]。この変更では、src/cpu/x64/zen64配下にZenDNNを呼び出すバックエンドが新設されています[5]。
初回実装の対象は、AOCL-DLP(AMD Optimizing CPU Libraries - Deep Learning Primitives)を経由するBF16およびFP32精度のMatMul(行列積)演算と融合後処理(fused post-ops)、ならびにデータ形式変換のためのReorderです[5, 6]。対象外の演算構成には既存のoneDNN実装へフォールバックする設計が採られており、oneDNNの公開APIに変更は加えられていません[5, 7]。そのため、PyTorchをはじめとするoneDNNの利用側フレームワークでは、ソースコードを変更せずに新バックエンドの最適化を利用できる構造が整えられています[5]。
補足:oneDNNとは
ディープラーニングアプリケーションの計算性能を向上させる、オープンソースのハードウェアアクセラレーションライブラリです。
統合の背景:x86 AIエコシステムの断片化解消と協業の狙い
今回の最適化集約は、業界団体であるx86 Ecosystem Advisory Groupの提言を受けた合意に基づいています[8]。
従来、x86 CPU向け推論の高速化は、ベンダーごとのライブラリやパッチを通じて進められてきました。例えば、AMDのZenDNNをPyTorchへ直接組み込む公開レビュー提案では、インフラとしてのZenDNNビルド対応と、bmm(バッチ行列積)およびSDPA(Scaled Dot-Product Attention)演算子の統合が、2件の主要PRに分けて示されていました[10]。このようにベンダーごとに最適化経路が分かれていると、エコシステムの断片化につながり、フレームワーク側の保守コストや開発者の負担が増大する要因となります。
IntelとAMDが掲げる協業の目的は、x86 AIエコシステムの断片化を抑え、両社のCPUをまたいでPyTorchアプリケーションを開発、保守、配備しやすくすることです[9]。
一方、AI Compute Extensions(ACE)のPyTorch対応は、将来のoneDNN更新を通じて実施される予定とされています[8, 11]。
後輩ライバル関係にある2社が共通ライブラリに集約するというのは、開発現場にとってどういう変化になるんですか?
先輩ベンダーごとに個別の最適化PRや独自拡張を追う負担が減って、同じPyTorch環境のまま複数世代のx86システムを管理しやすくなるよ。
後輩コードパスが1本にまとまれば、すぐにどのx86環境でも同じように動く状態になるんでしょうか?
先輩提供時期や対象バージョンの詳細はまだ公表されていないから、今後のリリース状況を見守る必要があるね。
呼出経路とアーキテクチャ:PyTorchからCPUカーネルへのディスパッチ機構
oneDNNは従来から、Intel 64およびAMD64アーキテクチャに基づくプロセッサ向けの最適化実装をsrc/cpu/x64配下に備えています[12, 13, 14]。今回の協業では、AMD64 CPU上で動作するoneDNNの基本機能に加え、ZenDNN由来の特化型最適化経路を共通構造内に追加します[12, 13, 14]。
oneDNNの設計議論では、フレームワーク側との接続処理をx86アーキテクチャごとに分岐させる方式を避け、通常のプリミティブ選択リスト(per-primitive dispatch list)にZenDNNを1つのエントリとして追加する方針が合意されました[15]。
この設計では、PyTorch側は従来と同じdnnl::matmulなどの共通APIを呼び出します[15, 16]。oneDNN内部のディスパッチャがプロセッサ種別を判定し、AMD CPU環境で条件を満たす場合にZenDNN経路を選択します[16, 17]。演算パラメータがZenDNNでサポートされていない場合は、既存のoneDNNネイティブ実装へフォールバックします[16]。Intel CPU環境では、従来のx64カーネル実装が引き続き呼び出されます[17]。共通APIの配下にCPUベンダーごとの固有カーネルがあるため、実際に選択される実装と性能特性は実行環境のCPUに依存します[17]。
補足:AOCL-DLPとは
AMD Optimizing CPU Librariesに含まれる、ディープラーニング向けの行列積演算などを最適化するライブラリです。
PyTorchフロントエンドからoneDNNプリミティブへの呼出フロー
PyTorchの推論処理は、PythonまたはC++ APIからATen演算層へ処理が渡されるところから始まります[19]。例えば、全結合層を担うat::native::linearの実装では、バイアスの有無やテンソルの性質に応じてat::addmmまたはat::matmulを内部で呼び出します[19]。
PyTorchでoneDNN(MKLDNN)バックエンドを利用するには、USE_MKLDNNを有効にしてビルドする必要があります[21]。実行時には、フラグtorch.backends.mkldnn.enabledで制御します[18, 21]。ただし、このフラグを有効にしても、すべてのLinear演算が一律にoneDNNへ渡されるわけではありません。演算対象のCPUハードウェア機能、データ型(dtype)、テンソルレイアウト、行列サイズに基づいて判定されます[21]。例えばMatMul演算では、サイズ判定($M \times N \times K \le 16 \times 16 \times 16$の小規模演算かどうかの分岐など)を経てディスパッチ先が決まります[21]。
MKLDNN固有の不透明なテンソルレイアウトを持つ場合は、MkldnnCPUディスパッチキーが適用され、ideep::inner_product_forward::computeが実行されます[20]。通常のテンソルレイアウトによるMatMul演算では、ideep::matmul_forward::computeが呼び出され、oneDNNのC++ APIへ処理が移譲されます[23]。また、CPU BLAS層でBF16精度のGEMMが要求されると、mkldnn_bf16_gemmの呼び出しを試み、成功した場合はその実行結果を返す分岐が組み込まれています[22]。FP32 MatMulの内部計算精度は、torch.backends.mkldnn.matmul.fp32_precisionの設定で制御できます[23]。
oneDNNはこれらの呼び出しを受け、行列積(MatMul)、畳み込み、Attention、正規化などの主要演算に最適化された処理を提供します[24]。さらに、活性化関数や残差接続を結合する後処理融合(Post-ops)を適用し、計算効率を高める構造を備えています[24]。
補足:ideepとは
PyTorchなどのフレームワークとoneDNNのC++ APIを仲介するブリッジライブラリです。
CPU機能検出とZenDNNバックエンドへの動的ディスパッチ
oneDNNのCPUエンジンは、実行時にCPUのハードウェア機能(ISA拡張など)を自動検出し、最適なJIT(Just-In-Time)コードを動的に生成してディスパッチするアーキテクチャを採用しています[25, 26]。プリミティブ記述子(primitive descriptor)は、エンジン種別と検出した機能に基づいて最適な実装を選択します[25]。
従来のPyTorch環境でZenDNNを利用する場合、利用者は独立したプラグインであるzentorchを導入していました[27]。zentorchはATen APIとZenDNN APIを接続するとともに、torch.compile向けのカスタムバックエンドとして、FXグラフ上の最適化パスを提供していました[27]。ZenDNN内部では、判断木やAutoTunerを通じて演算ごとに最適なライブラリ(AOCL-DLP、oneDNN、LibXSMM、FBGEMM、独自カーネル)を選択し、Low Overhead API(LowOHA)、融合後処理、FP16対応、MoE(Mixture of Experts)向けグループGEMM、重みキャッシングなどの最適化技術を適用してきました[28]。
PR #5511で導入されたZenDNNバックエンドは、こうした最適化技術の一部をoneDNNの通常のプリミティブ選択機構に組み込みました[29]。呼び出し元は標準のdnnl::matmulインタフェースを維持したまま、AMD CPUが実行時に検出されるとZenDNNのAOCL-DLPカーネルへディスパッチされます[29]。ZenDNNがサポートしていない演算パラメータが渡された場合は、status::unimplementedを返します。これを受けてoneDNNディスパッチャが、既存のJITカーネル(brgemm_matmul_tなど)へ処理を引き継ぎます[29]。
初回実装の適用範囲と性能検証の前提条件
PR #5511で実装されたZenDNN経路の適用範囲は限定されています。対象は、AOCL-DLPによるBF16およびFP32精度のMatMulと融合後処理、ならびにデータフォーマット変換用のReorderです[30, 31]。それ以外の演算構成やパラメータにはstatus::unimplementedが返され、既存のoneDNN実装へフォールバックします[31, 32]。
PR #5511のプルリクエストでは、本実装の効果を示すベンチマーク結果が公開されています。初期の検証報告では、6カ月以上前のvLLM+Nativeという古いベースラインとの比較が提示されていました。その後、レビュー担当者の指摘を受け、同一コードベース(PR #5511のリビジョン)でZenDNN経路の有効(Zen有効)と無効(Zen無効)を切り替えた比較データが追加されました[33]。
測定はAMD Turinプロセッサ(128コア、単一インスタンス)環境で、LLM推論基盤のvLLMを用いて実施されました。条件はバッチサイズ32、入力長128トークン、出力長128トークンです[34, 35]。評価された16モデルのスループット向上比(Zen有効/Zen無効)は、1.02倍から1.29倍の範囲でした[34]。
| 測定対象モデル | バッチサイズ | 入力長(tokens) | 出力長(tokens) | Zen有効/無効スループット比 |
|---|---|---|---|---|
| gpt-oss-20b-BF16 | 32 | 128 | 128 | 1.02倍 |
| Qwen3-30B-A3B | 32 | 128 | 128 | 1.05倍 |
| Qwen3.6-35B-A3B | 32 | 128 | 128 | 1.05倍 |
| Qwen3.5-4B | 32 | 128 | 128 | 1.06倍 |
| Qwen3.5-9B | 32 | 128 | 128 | 1.07倍 |
| Llama-3.1-8B-Instruct | 32 | 128 | 128 | 1.16倍 |
| InternVL3-8B | 32 | 128 | 128 | 1.21倍 |
| Qwen3-VL-8B-Instruct | 32 | 128 | 128 | 1.21倍 |
| gemma-4-E2B | 32 | 128 | 128 | 1.22倍 |
| gemma-4-E4B | 32 | 128 | 128 | 1.23倍 |
| Qwen2.5-VL-7B-Instruct | 32 | 128 | 128 | 1.23倍 |
| Qwen2.5-VL-3B-Instruct | 32 | 128 | 128 | 1.24倍 |
| InternVL3-2B | 32 | 128 | 128 | 1.25倍 |
| Qwen3-VL-2B-Instruct | 32 | 128 | 128 | 1.26倍 |
| Qwen3-14B-Instruct | 32 | 128 | 128 | 1.28倍 |
| Phi-4-reasoning-plus | 32 | 128 | 128 | 1.29倍 |
この測定結果を解釈する際には、いくつかの制約を考慮する必要があります。公開コメントにはTurin 128コア環境と記載されていますが、詳細なCPU型番、実際の割り当てスレッド数、NUMAノード配置、ワークロード全体の量子化・実行精度、反復試行回数やウォームアップの条件、スループット値の絶対単位は再掲されていません。そのため、測定環境を完全に再現することは困難です[35]。
また、最大の向上比(1.29倍)を示したPhi-4-reasoning-plusについて、提示されたBF16 MatMulのverboseログは一部の呼び出しに限られています。レビュー担当者は、抜粋ログの実行時間に大きな有意差が見られないとして、全ログの提出を求めました[36]。したがって、モデル全体のスループット比を、個々のMatMul形状における改善効果へ無条件に一般化することはできません[36]。
共通API配下に統合されても、すべてのx86 CPUや全演算で一律に最適化が働くわけではありません[37]。ZenDNN経路はAMD CPU専用の選択的バックエンドで、対象もBF16/FP32 MatMulなどに限られます[37]。Intel CPU環境では既存のカーネルが動作し、未対応の構成ではフォールバックするため、得られる性能特性はワークロードの構成とハードウェア環境によって異なります[37]。
実務者の移行判断と運用:ビルド条件・既存環境・適用確認
oneDNNのZenDNNバックエンドは、明示的なビルド設定で有効化する選択式機能(opt-in)です[38, 40, 42]。標準のビルド構成ではONEDNN_X64_USE_ZENはOFFに設定されています。ライブラリの配布者や保守者がONEDNN_X64_USE_ZEN=ONを明示して再ビルドする必要があります[38, 40, 42, 44]。
ZenDNNバックエンドのビルド環境には、以下の条件があります[39, 41, 43, 45]。対応プラットフォームはLinux x86_64で、Windows環境はビルド対象外です[39, 41]。ビルドツールにはCMake 3.26以降、コンパイラにはGCC 11.2以降またはClang 14以降が必要です[39, 41, 43, 45]。CPUランタイムにはOpenMP(ONEDNN_CPU_RUNTIME=OMP)を指定します[39, 41, 43, 45]。また、ZenDNN本体はバージョン6.0.0以降が必要です。事前にビルドしたZenDNNバイナリのパスをCMake変数ZENDNNROOTで指定してリンクします[38, 39, 40, 41, 42, 43, 44, 45]。ZenDNNはZen 4以降のマイクロアーキテクチャに対応しています[41]。外部のZenDNNを構築する場合、依存ライブラリの重複取り込みを防ぐため、ZENDNNL_DEPENDS_ONEDNN=OFFを指定するようoneDNNの公式ガイドが案内しています[46]。
| 設定項目 | 指定内容・要件 | 技術的補足 |
|---|---|---|
| 対象OS | Linux x86_64 | Windowsビルドは対象外 |
| ビルドツール | CMake 3.26以降 | 必須ビルドシステム |
| コンパイラ | GCC 11.2以降 または Clang 14以降 | C++コンパイラ要件 |
| CPUランタイム | ONEDNN_CPU_RUNTIME=OMP | OpenMPランタイムを指定 |
| ZenDNNライブラリ | ZenDNN 6.0.0以降 | Zen 4以降に対応した事前構築バイナリ |
| ZenDNN側オプション | ZENDNNL_DEPENDS_ONEDNN=OFF | ZenDNN内部でのoneDNN二重取り込みを防止 |
| 有効化フラグ | ONEDNN_X64_USE_ZEN=ON | 選択式バックエンド(既定値: OFF) |
| インストールパス指定 | ZENDNNROOT=<path> | 事前ビルド済みZenDNNの配置先ディレクトリ |
| 実行時ディスパッチ | AMD CPU実行時のみ有効化 | Intel CPU環境では既存実装を維持 |
PyTorchを利用するアプリケーション開発者にとって、公開APIに変更はないため、Pythonレイヤーのモデル定義コードを書き換える必要はありません[47, 48]。ただし、PyTorchの実行時フラグtorch.backends.mkldnn.enabledはoneDNN(MKLDNN)全体を有効化するもので、このフラグだけでZenDNN経路が有効になるわけではありません[48]。ZenDNNバックエンドを有効にしてビルドしたoneDNNを含むPyTorch環境を選ぶ必要があります[48]。
すでにzentorchを導入している環境では、移行判断に注意が必要です。AMDの公式資料によると、zentorchはATenとZenDNNを直接接続する独立プラグインで、専用のtorch.compileバックエンドによるFXグラフ最適化を提供しています[49]。今回のoneDNNへの統合は、初期段階ではBF16/FP32 MatMulやReorderを中心とした対応です。そのため、既存のzentorchを継続利用しながら、運用中のワークロードに必要な演算子やグラフ最適化が移行先でカバーされているか検証したうえで、移行を進めるのが妥当です[49]。
推論基盤の運用では、ZenDNN経路が意図どおり適用されているかを確認するために、PyTorchのverbose機能を利用できます。環境変数DNNL_VERBOSEを設定するか、PyTorch上でtorch.backends.mkldnn.verboseを有効にすると、実行時に選択されたカーネル名、入力データ形状、実行時間がログに出力されます[50, 51]。APIの呼び出し確認に加えて、実行時ログからフォールバックの有無や最適化カーネルの稼働状況を把握できます[51]。
後輩アプリケーション側のPythonコードを変えずに高速化できるなら、既存の環境もすぐに新しい構成へ切り替えてよいんでしょうか?
先輩初回実装でカバーされているのはBF16やFP32のMatMulとReorderが中心だから、既存の環境で使っている演算やグラフ最適化が移行されているかを確かめる必要があるね。
後輩コードを書き換えなくても、ビルド設定や実行環境が揃っていなければ従来のカーネルへフォールバックするわけですね。
先輩そうだね。verboseログを出力して、実際にZenDNNカーネルへディスパッチされているか確認してから移行を進めるのが確実だよ。



