2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

nVidia NPU と GPU とは結局、何が違うのか?

Posted at

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 などが同梱
  • 開発ツールやサンプルコード、デバッグ環境も一式揃っている

🔗 JetPack SDK - nVidia 公式


2. TensorRT

nVidiaが提供する AI推論最適化ライブラリ です。

  • PyTorch や TensorFlow で学習したモデルを推論向けに最適化
  • DLA(Deep Learning Accelerator)に処理を割り当て可能
  • FP16 や INT8 最適化にも対応

💡 DLAを指定して使う例(擬似コード):

builder->setDLACore(0); // DLA Core 0 に割り当て

🔗 TensorRT - nVidia 公式


✅ 開発の流れ(Jetson + DLAを活用する場合)

以下の手順で、nVidiaのNPUを使った推論が可能です。

  1. PyTorchやTensorFlowでモデルを学習
  2. モデルを ONNX形式 に変換
  3. TensorRTで最適化(trtexec などを利用)
  4. DLAに割り当てて推論を実行

✅ その他の主要NPUとSDK対応

nVidia以外の代表的なNPUと、それに対応するSDKは以下のとおりです。

メーカー デバイス例 SDK・ツール名
Google 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 での推論処理(バッファ確保 → 推論実行 → 出力取得)

前回のエンジン生成に加えて、ここでは 実際の推論処理部分 を含むコードを紹介します。


✅ 推論処理に必要な手順

  1. エンジンの読み込みと ExecutionContext の作成
  2. 入出力バッファの確保(CPU側とGPU側)
  3. 入力データの転送 → 推論実行 → 出力データの取得
  4. 結果の確認と後処理

✅ 推論処理の実装(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、単一入力/出力を想定した最小構成です。マルチバッチや動的形状対応が必要な場合は別途処理が必要です。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?