NV-TesseractはWSL2+RTX 5070 Tiで動く?時系列予測と異常検知を実測

NV-TesseractでETThの観測値から100点を予測したグラフ AI・機械学習
青が入力末尾168点、赤がNV-Tesseractの100点予測です。破線より右が未来側です。

実験機: Core i7-14700F、RTX 5070 Ti 16 GB、RAM 32 GB
環境: Windows 11、WSL 2、Ubuntu 26.04 LTS、Python 3.12.14、PyTorch 2.12.1+cu130(予測)/2.11.0+cu130(異常検知)

NV-Tesseractの公式サンプルを、WSL 2とRTX 5070 Tiで動かしました。時系列の100点予測と、500点のデータから異常箇所を探す処理まで実行できています。

名前は似ていますが、文字認識のTesseractとは別物です。こちらはNVIDIAの時系列データ用ライブラリで、予測と異常検知のモデルを使えます。導入ではチェックポイントの形状エラーに当たり、異常検知では乱数シードによって検出数が変わりました。

確認項目 結果
WSL 2からCUDAを認識 成功
ETThサンプルの100点予測 成功
予測1回目(モデル読込込み、重み取得済み) 6.881秒
同一プロセスの予測2回目 0.080秒
予測時のPyTorch ピーク allocated 2,824.5 MiB
AD Diffusionの500点異常検知 成功
異常検知のGPU使用率(200 ms間隔の最大値) 81%
異常検知のGPUメモリ(nvidia-smi最大値) 1,483 MiB

動きました。

異常検知の公式サンプルは、そのまま2回実行すると検出数が変わりました。PyTorch側の乱数も固定すると、2回の出力は完全に一致しました。

WSL2とRTX 5070 TiでNV-Tesseractを実行した結果画面
WSL 2上で取得した実測JSONをブラウザ表示した画面。予測100点、モデル読込込み6.881秒、同一プロセス再実行0.080秒を確認できます。

NV-Tesseractは何をするものか

NVIDIA公式リポジトリには、次の2モジュールが含まれています。

  • forecasting/: 過去の時系列から未来の値を予測する
  • ad_diffusion/: 複数センサーなどの時系列から異常候補を検出する

予測とは、たとえば直前512時間の負荷から、その後72時間や100時間の値を推定する処理です。異常検知は、入力をモデルで再構成し、元データとの差が大きい点を異常候補として扱います。今回の異常度はMAE(Mean Absolute Error、平均絶対誤差)で表されます。

公式要件はPython 3.12以上、PyTorch 2.7以上、pandas、NumPyです。GPUが推奨されていますが、CUDAが無い場合はCPUへフォールバックする設計です。今回はGPUで動くことを確かめるため、実行前にCUDAの認識まで確認しました。

必要なものと空き容量

必須

  • Windows 11とWSL 2
  • WSL側のUbuntu
  • WSLから利用できるNVIDIA GPUドライバ
  • Git
  • インターネット接続
  • 15 GB以上の空き容量(予測モジュールだけの目安)

あると確認しやすいもの

  • nvidia-smi
  • RTX系GPU
  • 16 GB程度のGPUメモリ

16 GBのVRAMを使い切ったわけではありません。予測のPyTorch ピーク allocatedは約2.76 GiBでした。ただし、この1条件だけから「すべての8 GB GPUで必ず動く」とまでは言えません。入力チャンネル数、バッチサイズ、説明機能、別チェックポイントで必要量は変わります。

ディスク側はやや重めです。このPCでは予測用.venvが約5.0 GB、NVIDIAの予測チェックポイントが約1.40 GB、MOMENT backboneが約1.39 GBでした。uvのダウンロードキャッシュも残るため、ぎりぎりの空き容量で始めない方が安全です。

管理者権限とWindows再起動は、すでにWSLとGPUドライバが動いていれば不要でした。WSLからCUDAを使える状態がまだ無い場合は、先に「Windows 11+WSL 2でPyTorchからRTX 5070 Tiを使う」の確認手順を通すと切り分けやすくなります。

WSL 2からGPUを確認する

まずUbuntuを開き、GPUとPythonを確認します。

/usr/lib/wsl/lib/nvidia-smi
python3 --version
git --version

このPCでは次を確認できました。

NVIDIA GeForce RTX 5070 Ti
Driver Version: 595.71
GPU Memory: 16303 MiB
Python 3.14.4
git version 2.53.0

システムPythonは3.14でしたが、NV-Tesseract用には3.12の隔離環境を作ります。プロジェクトごとにPythonとパッケージを分けると、別のPyTorch環境を壊しにくくなります。

uvとNV-Tesseractを導入する

このPCにはuvが無かったため、小さなbootstrap用venvへ入れました。

python3 -m venv ~/.venvs/nv-tesseract-bootstrap
~/.venvs/nv-tesseract-bootstrap/bin/python -m pip install --upgrade pip uv
~/.venvs/nv-tesseract-bootstrap/bin/uv --version

確認できたバージョンはuv 0.12.8です。続いて公式リポジトリを取得し、予測用環境を同期します。

git clone https://github.com/NVIDIA/NV-Tesseract.git
cd NV-Tesseract/forecasting
~/.venvs/nv-tesseract-bootstrap/bin/uv sync --python 3.12

初回はPyTorchとCUDA関連パッケージをまとめてダウンロードします。このPCでは91 パッケージが入りました。

リポジトリを/mnt/c配下へ置き、キャッシュをWSL filesystemへ置いたところ、uvはhardlinkを作れずコピーへ切り替わりました。処理自体は成功しますが、展開に約2分45秒かかりました。次の警告は失敗ではありません。

warning: Failed to hardlink files; falling back to full copy.
If the cache and target directories are on different filesystems,
hardlinking may not be supported.

Windowsから原稿やCSVを直接開きたかったので今回は/mnt/cを使いました。速度を優先する場合は、リポジトリとキャッシュを同じWSL filesystem側へ置く構成も検討できます。

PyTorchからRTX 5070 Tiが見えているか

予測を始める前に、作成されたPythonでCUDAを確認します。

.venv/bin/python -c "import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0)); print(torch.cuda.get_device_capability(0))"

実際の出力です。

2.12.1+cu130
13.0
True
NVIDIA GeForce RTX 5070 Ti
(12, 0)

torch.cuda.is_available()がTrueで、GPU名も一致しています。(12, 0)はcompute capabilityです。ここまで通れば、少なくとも「CPU版PyTorchを入れてしまった」「WSLからGPUが見えない」という段階は抜けています。

ETThの512点から100点を予測する

予測にはリポジトリ同梱のETTh_single_feature.csvを使いました。ETThは電力変圧器温度の時系列で、今回はLULL列の最後512点を入力し、その先100点を出します。

固定した条件は次のとおりです。

項目 設定
入力 公式ETTh single-feature サンプル
target LULL
入力長 seq_len 512
出力長 forecast_horizon 100
モデル native horizon 72
バッチサイズ 1
乱数シード 42
cross-channel 無効

最小構成は次のようになります。model_horizonは公開チェックポイントに合わせて72のままにします。

from pathlib import Path
import pandas as pd
from sdk.forecasting import ForecastingConfig, perform_forecasting

csv_path = Path("sdk/tests/datasets/ETTh_single_feature.csv")
df = pd.read_csv(csv_path).tail(512)

config = ForecastingConfig(
    timestamp_column="timestamp",
    target_column="LULL",
    seq_len=512,
    forecast_horizon=100,
    model_horizon=72,
    batch_size=1,
    num_workers=0,
    seed=42,
    use_cross_channel=False,
)

forecast = perform_forecasting(df=df, config=config)
forecast.to_csv("forecast.csv", index=False)
print(forecast.head(10))

初回はHugging Faceから重みを自動取得します。予測チェックポイントは約1.40 GB、MOMENT backboneは約1.39 GBでした。認証なしで取得できましたが、未認証リクエストのrate limit 警告は表示されました。

出力はtimestampとLULL_forecastを持つ100行のDataFrameです。先頭10点は次の値でした。

1.2353706, 1.3113322, 1.4206676, 1.4212670, 1.3020000,
1.4943643, 1.4871302, 1.5049992, 1.4743977, 1.4228201
NV-TesseractでETThの観測値から100点を予測したグラフ
青が入力末尾168点、赤がNV-Tesseractの100点予測です。破線より右が未来側で、予測値は1.24付近から始まり、後半では1.6台まで上がりました。

この図は「未来を正しく当てた」ことの証明ではありません。今回は実行可否と出力形状を確認する試験であり、予測区間の正解データとMAEを比較していないためです。精度評価では入力末尾をさらに手前へずらし、隠した100点と予測を比較する必要があります。

100点予測で起きたチェックポイント形状エラー

最初はforecast_horizon=100に合わせ、model_horizonも100へ変更しました。するとチェックポイント読込時に止まりました。

RuntimeError: Error(s) in loading state_dict for BackbonePipeline:
size mismatch for head.linear.weight:
checkpoint torch.Size([72, 65536])
current model torch.Size([100, 65536])

公開チェックポイントの予測headは72出力です。一方で100に作り替えたモデルは100出力を要求するため、重みの形が合いません。

修正はmodel_horizon=72へ戻し、forecast_horizon=100だけを指定することでした。SDKはnative horizonを超えた残り28点を自己回帰で延長します。NVIDIAのモデル cardにも、native capabilityを超えるhorizonはautoregressive extensionに対応すると記載されています。

正直、100点欲しいから両方100にする、という設定はそれっぽく見えます。チェックポイントの出力層まで変わるのが厄介です。

モデル読込込みとウォームアップ後回を分けて測る

同じ入力を同一プロセス内で2回実行しました。どちらも重みファイルはダウンロード済みです。

回 含まれる処理 時間 PyTorch ピーク allocated ピーク reserved
1 チェックポイント読込+モデル構築+推論 6.881秒 2,824.5 MiB 2,828 MiB
2 キャッシュ済みモデル+推論 0.080秒 2,060.9 MiB 2,082 MiB

1回目を「純粋な推論速度」と呼ぶのは不正確です。モデルの読込とGPUへの配置が含まれています。2回目はSDK内のモデルキャッシュを再利用しており、100点の出力は1回目と一致しました。

また、初回重みダウンロードはこの表に含めていません。回線速度で大きく変わるため、ダウンロード、モデル読み込み、ウォームアップ後推論は分けて扱う方が結果を読みやすくなります。

AD Diffusionで500点の異常検知を動かす

異常検知側は別の依存関係を持つため、ad_diffusionにも独立した環境を作りました。

cd ../ad_diffusion
~/.venvs/nv-tesseract-bootstrap/bin/uv sync --python 3.12
.venv/bin/python examples/quick_example.py --download-weights
.venv/bin/python examples/quick_example.py

異常検知チェックポイントのfinal_model.pthは約29.6 MBです。公式quick 例は乱数シード 42で500点・3 sensorの合成時系列を作り、spike、dip、段階 shift、noiseを混ぜます。推論はDPM-Solver 20ステップ、nsample=15でした。

最初の実行は約13.58秒で推論し、21点を異常として検出しました。precision 1.000、再現率 0.171、F1 0.292です。

precisionが1.000なので、検出した点にfalse positiveはありません。一方、再現率 0.171なので、正解ラベルの多くを拾えていません。少数の強い異常だけを選んだ状態です。公式サンプルが完走したことと、運用に十分な検出性能であることは分けて考える必要があります。

同じ公式サンプルなのに検出数が変わる

GPU使用量を200 ms間隔で記録しながら公式例を2回実行すると、結果は次のように変わりました。

回 検出数 TP FP FN precision 再現率 F1 total elapsed
1 18 18 0 105 1.000 0.146 0.255 27.575秒
2 24 24 0 99 1.000 0.195 0.327 28.105秒

入力データは同じです。公式例は合成データ生成用のnp.random.seed(42)を設定していますが、拡散モデルが使うPyTorchの乱数までは固定していません。

そこで、各回前に次を追加しました。

import numpy as np
import torch

np.random.seed(42)
torch.manual_seed(42)
torch.cuda.manual_seed_all(42)

乱数シード固定後は2回とも23点を検出し、Anomaly列は完全一致、MAEの最大絶対差も0でした。実行時間は14.082秒と12.792秒です。

NV-Tesseract AD Diffusionの合成センサーデータ、正解異常、検出異常、MAE
上段の黄丸が正解異常、赤い×が乱数シード固定後に検出した異常です。下段は再構成MAEで、赤点がthresholdを超えた箇所です。目立つ異常でも未検出の箇所があり、高precisionと低再現率を視覚的にも確認できます。

乱数シード固定後の混同行列はTP 23、FP 0、FN 100、TN 377でした。precision 1.000、再現率 0.187、F1 0.315です。

ここから分かるのは、乱数シードを固定すれば同じ環境・同じ入力で結果を再現できることです。検出精度が高いという意味ではありません。threshold strategy、nsample、前処理、実データへの追加学習は別途評価が必要です。

GPUが本当に使われたか

AD Diffusion実行中にnvidia-smiを200 ms間隔で取得しました。

指標 観測した最大値
GPU 使用率 81%
GPUメモリ used 1,483 MiB
power draw 219.3 W

torch.cuda.is_available()だけでなく、推論中にGPU使用率と消費電力が上がったため、実計算がGPUへ渡ったことを確認できます。ただし200 ms間隔のサンプルなので、サンプル間にある瞬間的なピークを取り逃す可能性があります。

予測側の2,824.5 MiBはPyTorch allocatorがプロセス内で記録したピーク allocated、異常検知側の1,483 MiBはnvidia-smiが見たデバイス全体の使用量です。測り方が違うため、両者をそのままモデル間のVRAM比較には使えません。

よく止まりそうな箇所

torch.cuda.is_available()がFalse

NV-Tesseractより手前の問題です。Windows側ドライバ、WSL update、CUDA版PyTorchの順に確認します。WSL内へ通常のLinux用NVIDIA ドライバを重ねて入れる前に、Windows側ドライバがWSLへ公開されているかを確認した方が安全です。

100出力チェックポイントのサイズ mismatch

forecast_horizon=100でもmodel_horizonは公開チェックポイントの72へ合わせます。100へ変えるのは出力要求側だけです。

Hugging Faceの401/403

今回は認証なしでダウンロードできました。401や403が出る場合は、モデル pageの利用条件、Hugging Face側のライセンス acceptance、トークン設定を公式READMEに沿って確認します。トークンは記事やログへ貼らないでください。

diskが急に減る

予測environment、CUDA パッケージ、NVIDIA チェックポイント、MOMENT backbone、ダウンロードキャッシュが別々に存在します。du -sh .venvとキャッシュディレクトリを確認します。削除前に、どのenvironmentが参照しているかを確かめてください。

実行ごとに異常数が変わる

合成データ用のNumPy 乱数シードだけでは足りません。PyTorchとCUDA側の乱数シードも固定します。それでもGPU演算によっては完全決定的にならない演算子があるため、出力差を測って確認するのが確実です。今回はMAE最大絶対差0まで確認しました。

この結果から判断できること

WSL 2、RTX 5070 Ti、CUDA 13.0系PyTorchの組み合わせで、NV-Tesseractの時系列予測とAD Diffusionは動作しました。予測は公式ETTh サンプルから100点を返し、異常検知は公式の500点サンプルをGPUで処理できています。

導入上の注意は、VRAMより先にダウンロード容量とPython環境の分離です。予測は公開重みだけで約2.8 GBあり、CUDA dependencyを含むvenvも約5 GBになりました。一方、今回の予測時PyTorch ピーク allocatedは約2.76 GiBでした。

また、公式quick 例の数値をベンチマーク表へそのまま転記するのは危険です。異常検知はPyTorch 乱数シードを固定しないと検出数が変わり、precision 1.0でも再現率は0.2未満でした。少なくとも乱数シード、入力、sampling条件、threshold、計測方法を固定してから比較する必要があります。

今回動作を確認できたのは、このPCでのリポジトリ同梱サンプルです。実センサーの異常を十分に検出できるか、別GPUでも同じ速度が出るか、CPU 切り替えが実用的な速度かは、この結果からは判断できません。

再現に使った生成ファイル

検証スクリプトでは、次を生データとして保存しました。

  • 予測100点のCSVを2回分
  • Python、PyTorch、CUDA、GPU、commit hash、条件を含むJSON
  • GPUメモリ、使用率、powerの200 ms サンプル
  • AD Diffusionの結果CSVと正解ラベル
  • 乱数シード固定前後の混同行列
  • console ログと未丸めのelapsed time

リポジトリはcommit b68ea6f946b9b299d48f91673fd722366c150e99を使用しました。NV-Tesseractは更新が続いているため、結果が変わった場合はcommit hashとlock ファイルから先に確認すると追いやすくなります。

参考資料

関連するGPU測定方法は、バッチサイズと処理速度・VRAM・CUDA OOMの実測でも条件を分けて整理しています。