AIで利用される nVidia NPU とはなにか?GPUとの違いは?
近年、AIの進化とともに、**NPU(Neural Processing Unit)**という言葉を耳にする機会が増えました。この記事では、特にnVidia製品に焦点を当てて、NPUとは何か、GPUとの違いは何かについてわかりやすく解説します。
✅ NPUとは?
**NPU(ニューラル・プロセッシング・ユニット)**は、その名のとおり、ニューラルネットワークの処理に特化した専用プロセッサです。
主な特徴:
- 行列演算に最適化されたアーキテクチャ
- 高速かつ省電力でAI推論が可能
- 特定用途(画像認識、音声認識など)に最適化
特にエッジAI(スマートフォン、車載機器、IoT端末など)においては、CPUやGPUよりも低消費電力で高効率な推論処理が求められるため、NPUの導入が進んでいます。
✅ nVidiaにおけるNPUの位置づけ
nVidiaのAI関連製品において、「NPU」という言葉はあまり前面には出てきません。しかし、実質的にNPU的な役割を果たしているコンポーネントがあります。
代表的なもの:
-
Tensor Cores(テンソルコア)
→ Volta世代(Tesla V100など)から搭載された、行列乗算に特化したGPU内の演算ユニット -
Deep Learning Accelerator(DLA)
→ Jetsonシリーズなどに搭載されている、AI推論専用の軽量NPU。CPUやGPUの負荷を下げ、省電力に貢献。
✅ GPUとの違い
項目 | GPU | NPU(またはDLA) |
---|---|---|
主な用途 | 汎用的な並列演算(CG描画、AI学習など) | AI推論(特化用途) |
最適化対象 | 幅広い用途(グラフィックス・科学技術演算) | ニューラルネットワークの推論処理 |
柔軟性 | 高い(CUDAなどで汎用コードも実行可能) | 低い(特定モデル専用の命令セット) |
消費電力 | 高め | 低め |
レイテンシ | 比較的高い | 極めて低い |
nVidia製品の例 | RTX, Tesla, A100 など | Jetson Orin の DLA, Grace Hopper など |
✅ どちらがAIに向いているのか?
用途に応じて使い分けることが重要です。
- AI学習(トレーニング) → 高度な行列演算が必要:GPU(特にTensor Core)
- AI推論(インファレンス) → 省電力かつ高速な応答が重要:NPU / DLA
たとえば、クラウド側ではA100やH100などのハイエンドGPUで学習を行い、エッジデバイスではJetson Orinに搭載されたDLAで推論する、といった使い分けが行われます。
✅ NPU vs GPU まとめ
- NPUはAI推論に特化したプロセッサ
- nVidia製品では、Tensor CoreやDLAがNPU的な役割を果たす
- GPUは学習、NPUは推論での活躍が期待される
- 用途やデバイスの制約に応じて使い分けることが大切
NPUを利用したプログラムを書きたい。nVidiaのSDKは?
AI推論を高速・省電力で実行するために注目されている NPU(Neural Processing Unit)。nVidia製のJetsonシリーズなどに搭載されているNPU(たとえばDLA)を使ったプログラムを書くには、専用のSDKやツールが必要です。
この記事では、nVidia製NPUを活用するためのSDKや開発フローをわかりやすくまとめます。
✅ nVidia NPU(DLA)で使える主要SDK
1. JetPack SDK
Jetsonシリーズ(Jetson Nano / Xavier / Orinなど)向けに提供される統合ソフトウェアパッケージです。
- CUDA / cuDNN / TensorRT / OpenCV などが同梱
- 開発ツールやサンプルコード、デバッグ環境も一式揃っている
2. TensorRT
nVidiaが提供する AI推論最適化ライブラリ です。
- PyTorch や TensorFlow で学習したモデルを推論向けに最適化
- DLA(Deep Learning Accelerator)に処理を割り当て可能
- FP16 や INT8 最適化にも対応
💡 DLAを指定して使う例(擬似コード):
builder->setDLACore(0); // DLA Core 0 に割り当て
✅ 開発の流れ(Jetson + DLAを活用する場合)
以下の手順で、nVidiaのNPUを使った推論が可能です。
- PyTorchやTensorFlowでモデルを学習
- モデルを ONNX形式 に変換
- TensorRTで最適化(
trtexec
などを利用) - DLAに割り当てて推論を実行
✅ その他の主要NPUとSDK対応
nVidia以外の代表的なNPUと、それに対応するSDKは以下のとおりです。
メーカー | デバイス例 | SDK・ツール名 |
---|---|---|
Coral Edge TPU | Edge TPU SDK / PyCoral | |
Intel | Myriad X / Neural Compute | OpenVINO |
Apple | Apple Neural Engine (ANE) | Core ML / Create ML |
MediaTek | Dimensityシリーズ | NeuroPilot SDK |
Huawei | Ascend シリーズ | MindSpore / Ascend Toolkit |
✅ 注意点とTips
- nVidiaのDLAは推論専用で、学習には使えません
- TensorRTでは、サポート外のレイヤー構成は自動的にGPUにフォールバックされます
- JetPackとTensorRTのバージョンは互換性が重要なので、必ず対応表を確認しましょう
✅ SDK まとめ
- JetsonなどnVidia製NPUを使うには JetPack SDK + TensorRT が王道
- 推論エンジンとしてTensorRTを使い、DLAコアを明示的に指定することでNPUを活用可能
- モデル変換にはONNX形式が広く使われており、PyTorchやTensorFlowから簡単に移行可能
Jetson Orin での推論サンプルコード(TensorRT + ONNX)
このサンプルでは、Jetson Orin 上で TensorRT を用いて ONNX モデルを推論する基本的な C++ コードを紹介します。
ONNX モデルはすでに変換済みであることを前提としています(例: model.onnx
)。
✅ 環境準備(JetPack SDK がインストール済みであること)
sudo apt update
sudo apt install -y libnvinfer8 libnvinfer-dev libnvinfer-plugin8 libnvonnxparsers8 libnvparsers8 libnvinfer-bin
✅ C++ サンプルコード(推論)
#include <NvInfer.h>
#include <NvOnnxParser.h>
#include <cuda_runtime_api.h>
#include <fstream>
#include <iostream>
#include <vector>
using namespace nvinfer1;
class Logger : public ILogger {
public:
void log(Severity severity, const char* msg) noexcept override {
if (severity <= Severity::kINFO) std::cout << msg << std::endl;
}
};
int main() {
Logger logger;
IBuilder* builder = createInferBuilder(logger);
const auto explicitBatch = 1U << static_cast<uint32_t>(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
INetworkDefinition* network = builder->createNetworkV2(explicitBatch);
auto parser = nvonnxparser::createParser(*network, logger);
if (!parser->parseFromFile("model.onnx", static_cast<int>(ILogger::Severity::kINFO))) {
std::cerr << "Failed to parse ONNX model." << std::endl;
return -1;
}
IBuilderConfig* config = builder->createBuilderConfig();
config->setMaxWorkspaceSize(1 << 20); // 1MB
// ✅ DLAコアを使用したい場合は以下を有効にする
if (builder->getNbDLACores() > 0) {
config->setFlag(BuilderFlag::kGPU_FALLBACK);
config->setDefaultDeviceType(DeviceType::kDLA);
config->setDLACore(0); // DLAコア0を指定
}
ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
if (!engine) {
std::cerr << "Failed to build engine." << std::endl;
return -1;
}
std::cout << "Successfully built TensorRT engine." << std::endl;
engine->destroy();
network->destroy();
config->destroy();
builder->destroy();
parser->destroy();
return 0;
}
✅ ビルド方法(CMakeなしの場合)
g++ -std=c++17 -o infer_sample infer_sample.cpp \
-I/usr/include/aarch64-linux-gnu \
-lnvinfer -lnvonnxparser -lcudart
✅ 実行
./infer_sample
✅ 補足
- ONNXモデルの事前準備は、PyTorch → ONNX 変換などで済ませてください
- 入出力テンソルの設定、バッファの確保などはこの後の実装に含まれます
- 上記は最小構成の例で、実運用では
IExecutionContext
を使って推論を行います
Jetson Orin での推論処理(バッファ確保 → 推論実行 → 出力取得)
前回のエンジン生成に加えて、ここでは 実際の推論処理部分 を含むコードを紹介します。
✅ 推論処理に必要な手順
- エンジンの読み込みと ExecutionContext の作成
- 入出力バッファの確保(CPU側とGPU側)
- 入力データの転送 → 推論実行 → 出力データの取得
- 結果の確認と後処理
✅ 推論処理の実装(C++)
#include <NvInfer.h>
#include <cuda_runtime_api.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <cassert>
using namespace nvinfer1;
// ユーティリティ関数:ファイルからエンジンを読み込む
ICudaEngine* loadEngine(const std::string& engineFile, ILogger& logger) {
std::ifstream file(engineFile, std::ios::binary);
if (!file) return nullptr;
file.seekg(0, file.end);
size_t size = file.tellg();
file.seekg(0, file.beg);
std::vector<char> buffer(size);
file.read(buffer.data(), size);
IRuntime* runtime = createInferRuntime(logger);
return runtime->deserializeCudaEngine(buffer.data(), size);
}
int main() {
Logger logger;
// 1. エンジンのロードと ExecutionContext の作成
ICudaEngine* engine = loadEngine("model.trt", logger);
assert(engine);
IExecutionContext* context = engine->createExecutionContext();
assert(context);
// 2. 入出力インデックスとサイズ
int inputIndex = engine->getBindingIndex("input");
int outputIndex = engine->getBindingIndex("output");
auto inputDims = engine->getBindingDimensions(inputIndex);
auto outputDims = engine->getBindingDimensions(outputIndex);
size_t inputSize = 1;
size_t outputSize = 1;
for (int i = 0; i < inputDims.nbDims; ++i) inputSize *= inputDims.d[i];
for (int i = 0; i < outputDims.nbDims; ++i) outputSize *= outputDims.d[i];
inputSize *= sizeof(float);
outputSize *= sizeof(float);
// 3. ホスト & デバイスメモリ確保
float* inputHost = new float[inputSize / sizeof(float)];
float* outputHost = new float[outputSize / sizeof(float)];
void* inputDevice;
void* outputDevice;
cudaMalloc(&inputDevice, inputSize);
cudaMalloc(&outputDevice, outputSize);
// 任意の入力を用意(例: すべて 1.0f)
for (size_t i = 0; i < inputSize / sizeof(float); ++i)
inputHost[i] = 1.0f;
// 4. 推論の流れ
cudaMemcpy(inputDevice, inputHost, inputSize, cudaMemcpyHostToDevice);
void* bindings[] = {inputDevice, outputDevice};
context->executeV2(bindings);
cudaMemcpy(outputHost, outputDevice, outputSize, cudaMemcpyDeviceToHost);
// 出力を確認(先頭10個だけ表示)
for (int i = 0; i < std::min((size_t)10, outputSize / sizeof(float)); ++i)
std::cout << "output[" << i << "] = " << outputHost[i] << std::endl;
// クリーンアップ
cudaFree(inputDevice);
cudaFree(outputDevice);
delete[] inputHost;
delete[] outputHost;
context->destroy();
engine->destroy();
return 0;
}
✅ コンパイル方法
g++ -std=c++17 -o run_infer run_infer.cpp \
-I/usr/include/aarch64-linux-gnu \
-lnvinfer -lcudart
✅ 実行方法
./run_infer
✅ 補足
-
model.trt
は TensorRT エンジンファイルです(ONNX から事前に生成しておく) - 入力名
"input"
と出力名"output"
はモデルによって異なるため、確認が必要です - 実運用ではバッチサイズ対応や非同期処理も考慮してください
C++からのTensorRT の使い方を紹介しました。
しかし、大半の処理が GPU or NPU 側に存在するため
CPU側のコードをC/C++で最適化しても、全体的に見たときの高速化は限定的です。
そのため、CPU側の制御をPythonで記述しても大差ないため、便宜性で圧倒する
PythonからのTensorRTがAI業界の主流となっています。
そこで、Python 版の TensorRT 推論コードについても紹介していきます。
Jetson Orin での推論処理(Python + TensorRT)
このページでは、Python で TensorRT を使用して ONNX モデルを推論する方法を紹介します。Jetson Orin 上で簡潔に動作確認ができるスクリプトです。
✅ 必要なライブラリのインストール(Jetson 上)
JetPack SDK に含まれている TensorRT Python バインディングが必要です。以下のコマンドで確認できます:
python3 -c "import tensorrt; print(tensorrt.__version__)"
ONNX Runtime や NumPy も使用します:
sudo apt install python3-pip
pip3 install onnx onnxruntime numpy
✅ Python コード(TensorRT 推論)
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit # 自動でCUDAコンテキスト初期化
import numpy as np
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
def load_engine(trt_engine_path):
with open(trt_engine_path, "rb") as f, trt.Runtime(TRT_LOGGER) as runtime:
return runtime.deserialize_cuda_engine(f.read())
def allocate_buffers(engine):
h_input = cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(0)), dtype=np.float32)
h_output = cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(1)), dtype=np.float32)
d_input = cuda.mem_alloc(h_input.nbytes)
d_output = cuda.mem_alloc(h_output.nbytes)
return h_input, d_input, h_output, d_output
def infer(engine, h_input, d_input, h_output, d_output):
with engine.create_execution_context() as context:
cuda.memcpy_htod(d_input, h_input)
bindings = [int(d_input), int(d_output)]
context.execute_v2(bindings)
cuda.memcpy_dtoh(h_output, d_output)
return h_output
# モデルの準備
engine = load_engine("model.trt")
# バッファの準備
h_input, d_input, h_output, d_output = allocate_buffers(engine)
# 任意の入力を設定(例: 全て1.0)
h_input[:] = 1.0
# 推論の実行
output = infer(engine, h_input, d_input, h_output, d_output)
# 結果表示(先頭10個)
for i in range(min(10, len(output))):
print(f"output[{i}] = {output[i]}")
✅ 実行方法
python3 run_infer.py
✅ 補足
-
model.trt
は事前にtrtexec
などで作成しておいてください。 - 入力名や形状はモデルにより異なります。必要に応じて
engine.get_binding_name(0)
で確認できます。 -
pycuda
のインストールが必要です(pip3 install pycuda
)
このコードはバッチサイズ1、単一入力/出力を想定した最小構成です。マルチバッチや動的形状対応が必要な場合は別途処理が必要です。