概要
推論(インファレンス:Inference)とは、事前にデータから学習・訓練された機械学習モデルに対して新しい入力データを与え、そのモデルが持つ知識(重みパラメータ)をもとに予測・分類・検出などの結果を算出する処理のことです。
機械学習の処理フェーズは大きく「学習(トレーニング)」と「推論(インファレンス)」の二つに分かれます。
| フェーズ | 処理内容 | 計算リソース | 場所 |
|---|---|---|---|
| 学習(Training) | 大量データからパラメータを最適化 | 大規模GPU/TPUが必要 | クラウド・データセンター |
| 推論(Inference) | 学習済みモデルで新データに予測 | 軽量でOK | クラウド or エッジ |
組み込み・IoTシステムにおけるAI活用では、学習済みモデルを用いた推論をエッジデバイス上でリアルタイムに実行することが核心的な技術課題となります。
歴史・背景
推論という概念自体は機械学習の黎明期から存在していましたが、ディープラーニング以前の時代は線形モデルやSVM(サポートベクターマシン)が主流で、推論の計算コストは比較的小さいものでした。
2012年にAlexNetが画像認識コンテストILSVRCで圧倒的な成績を収めて以降、ディープニューラルネットワーク(DNN)が主流となり、推論に必要な計算量も急増しました。初期のDNNは推論に専用GPU上でも数十msを要し、CPUでは数秒以上かかるものも多くありました。
推論高速化の歴史的流れ:
- 2013〜2015年:CUDNNなどのGPU最適化ライブラリが登場し、クラウド推論が実用化
- 2017年:Googleが量子化(INT8推論)をTensorFlowに統合、CPU推論速度が大幅向上
- 2018年:TensorRT・OpenVINOなどのエッジ向け推論最適化エンジンが登場
- 2019年:TensorFlow Lite Microでマイコン上の推論が実現
- 2020年代:専用NPUの普及により、スマートフォンや組み込みSoCで高速かつ省電力な推論が標準化
技術仕様
ニューラルネットワークの推論計算
ディープラーニングモデルの推論は、レイヤー(層)を順番に通過するフォワードパス(順伝播)です。各レイヤーで行われる基本演算は次のとおりです。
全結合層(Fully Connected Layer):
y = W · x + b
x:入力ベクトル(n次元)W:重み行列(m×n)b:バイアスベクトル(m次元)y:出力ベクトル(m次元)
この行列積(GEMM: General Matrix Multiply)が推論の主要な計算カーネルです。
たたみ込み層(Conv2D)の擬似コード:
// 4次元テンソルのたたみ込み(簡略版)
for (int oc = 0; oc < out_channels; oc++) {
for (int oh = 0; oh < out_height; oh++) {
for (int ow = 0; ow < out_width; ow++) {
float sum = bias[oc];
for (int ic = 0; ic < in_channels; ic++) {
for (int kh = 0; kh < kernel_h; kh++) {
for (int kw = 0; kw < kernel_w; kw++) {
int ih = oh * stride + kh;
int iw = ow * stride + kw;
sum += input[ic][ih][iw] * weight[oc][ic][kh][kw];
}
}
}
output[oc][oh][ow] = activation(sum); // ReLUなど
}
}
}
推論精度とデータ型
| データ型 | ビット幅 | 精度 | メモリ | 速度 |
|---|---|---|---|---|
| FP32 | 32bit | 最高 | 基準 | 基準 |
| FP16 | 16bit | 高い | 1/2 | 2x |
| BF16 | 16bit | FP32近似 | 1/2 | 2x |
| INT8 | 8bit | 中 | 1/4 | 4x |
| INT4 | 4bit | 低め | 1/8 | 8x |
マイコンやNPUでの推論では主にINT8が使われます。量子化により浮動小数点モデルを整数型に変換することで、精度をわずかに犠牲にして大幅な速度・電力効率向上を実現します。
推論レイテンシの要因
推論レイテンシ = 前処理時間 + 実推論時間 + 後処理時間
実推論時間 ≈ (総演算量[FLOPS]) / (ハードウェアの実効演算性能[FLOPS/s])
| 要因 | 詳細 |
|---|---|
| モデルの深さ・幅 | レイヤー数・チャンネル数が多いほど遅い |
| データ型 | INT8はFP32の4倍以上速い場合がある |
| メモリ帯域 | パラメータのロードがボトルネックになりやすい |
| キャッシュ効率 | L1/L2キャッシュに収まるかどうか |
| バッチサイズ | エッジでは通常バッチサイズ1 |
動作原理
推論パイプラインの全体像
入力データ(画像/音声/センサー値)
↓
① 前処理(Pre-processing)
- リサイズ、正規化、データ型変換
- 例:[0,255] → [0.0, 1.0]
↓
② 推論実行(Inference Execution)
- フォワードパス(レイヤー順次計算)
- Conv2D → BN → ReLU → Pooling → ...
↓
③ 後処理(Post-processing)
- Softmax、NMS(非最大値抑制)、閾値処理
↓
出力結果(クラスラベル/バウンディングボックス/スコア)
デリゲーション(委譲)の仕組み
TensorFlow Liteなどの推論ランタイムは、演算ごとに最適なハードウェアへ処理を委ねるデリゲーション機能を持ちます。
import tflite_runtime.interpreter as tflite
# NNAPIデリゲート(AndroidのNPU/DSP活用)
delegate = tflite.load_delegate('libnnapi.so')
interpreter = tflite.Interpreter(
model_path='model.tflite',
experimental_delegates=[delegate]
)
C言語での組み込み推論実装例(TFLite Micro)
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "model_data.h" // モデルをC配列として埋め込み
// テンソルアリーナ(RAM領域)
constexpr int kTensorArenaSize = 32 * 1024;
uint8_t tensor_arena[kTensorArenaSize];
// オペレータ登録
tflite::MicroMutableOpResolver<5> resolver;
resolver.AddConv2D();
resolver.AddDepthwiseConv2D();
resolver.AddFullyConnected();
resolver.AddSoftmax();
resolver.AddReshape();
// インタープリタ生成
tflite::MicroInterpreter interpreter(
tflite::GetModel(g_model_data),
resolver,
tensor_arena,
kTensorArenaSize
);
interpreter.AllocateTensors();
// 推論実行
TfLiteTensor* input = interpreter.input(0);
memcpy(input->data.f, input_data, sizeof(float) * input_size);
interpreter.Invoke();
// 結果取得
TfLiteTensor* output = interpreter.output(0);
float result = output->data.f[0];
用途・ユースケース
リアルタイム推論が要求される場面
| 用途 | 要求レイテンシ | 典型的モデル |
|---|---|---|
| 自動車の物体検出 | 10ms以下 | YOLOv8n |
| 音声ウェイクワード | 50ms以下 | DS-CNN |
| 外観検査 | 100ms以下 | MobileNetV2 |
| 振動異常検知 | 500ms以下 | 1D-CNN |
| スマートメーター | 数秒以内 | LSTM |
バッチ vs リアルタイム推論
エッジデバイスでは通常、1サンプルずつ処理するオンライン推論(バッチサイズ=1)が一般的です。クラウドではバッチ処理でスループットを最大化しますが、エッジでは遅延を優先します。
実装・開発のポイント
ベンチマーク手法
推論性能を正確に測定するには以下のツールを使用します。
# TFLite Benchmarkツール
adb shell /data/local/tmp/benchmark_model \
--graph=/data/local/tmp/model.tflite \
--num_threads=4 \
--use_nnapi=true \
--num_runs=100
# 出力例
# Inference timings: Init: 5000 us, First inference: 12000 us,
# Warmup (avg): 11500 us, Inference (avg): 10800 us
メモリ最適化
組み込みシステムでは、テンソルアリーナのサイズをできるだけ小さくする必要があります。
# モデルのメモリ使用量を確認
import tflite_runtime.interpreter as tflite
interpreter = tflite.Interpreter('model.tflite')
interpreter.allocate_tensors()
print("テンソルの詳細:")
for detail in interpreter.get_tensor_details():
shape = detail['shape']
dtype = detail['dtype']
size = 1
for s in shape:
size *= s
print(f" {detail['name']}: shape={shape}, dtype={dtype}, "
f"size={size * dtype.itemsize} bytes")
精度劣化の確認
量子化や変換後に精度が落ちていないかを確認することが重要です。
# 元のFP32モデルとINT8量子化モデルの精度比較
def evaluate_model(interpreter, test_data, test_labels):
correct = 0
for data, label in zip(test_data, test_labels):
interpreter.set_tensor(input_idx, data[np.newaxis])
interpreter.invoke()
pred = np.argmax(interpreter.get_tensor(output_idx))
if pred == label:
correct += 1
return correct / len(test_data)
fp32_acc = evaluate_model(fp32_interpreter, test_data, test_labels)
int8_acc = evaluate_model(int8_interpreter, test_data, test_labels)
print(f"FP32精度: {fp32_acc:.4f}, INT8精度: {int8_acc:.4f}")
print(f"精度低下: {(fp32_acc - int8_acc) * 100:.2f}%")
他技術との比較
推論ランタイムの比較
| ランタイム | 対応ハードウェア | 対象ユースケース | 特徴 |
|---|---|---|---|
| TensorFlow Lite | ARM, x86, DSP, NPU | モバイル〜MCU | Googleエコシステム、豊富なサポート |
| TFLite Micro | Cortex-M | マイコン | 数十KB動作、C++実装 |
| ONNX Runtime | CPU, GPU, NPU | クロスプラットフォーム | 多様なフレームワーク対応 |
| TensorRT | NVIDIA GPU | 高性能エッジ | 最高速、NVIDIA専用 |
| OpenVINO | Intel CPU/GPU/VPU | Intel製品 | Intel最適化 |
| ArmNN | Arm CPU/GPU/NPU | Arm製品 | Arm純正 |
推論処理はエッジAIの核心であり、推論アクセラレータ・量子化・TensorFlow Lite・ONNXなどの関連技術と組み合わせることで、最適なエッジAIシステムを構築できます。