SPSS ModelerでIBM Granite Time Series Modelを使って時系列予測をしてみる その１ 準備編

# はじめに
IBMより、Granite Time Series Modelがリリースされました。
オープンソースのため、誰でも利用が可能です。

今回は、SPSS Modelerでこのモデルを活用していこうと思います。

マニュアルは以下

https://www.ibm.com/docs/ja/watsonx/saas?topic=solutions-forecast-future-values

以下の記事では、Watsonx.ai上のモデルをAPIで利用している例が紹介されています。

https://qiita.com/thayate/items/0968511f8f5508d8cbe3

Watsonx.ai上のモデルを使う場合は、IBM CloudのIDが必要になります。

https://cloud.ibm.com/docs/account?topic=account-account-getting-started&locale=ja

そのため、今回はHugging Faceに公開されているモデルをSPSS Modelerで利用する方法を紹介しようと思います。



## 1. Granite時系列モデルとは
IBMより以下のとおり発表されております。

•IBM Researchが開発したコンパクトな多変量時系列予測の基盤モデル
•CPUのみでも実行可能な軽量モデルを提供
•Apache 2.0ライセンスでオープンソースとして公開

このモデルは、Watsonx.ai上のものをAPIで呼び出して利用可能なことと、
Hugging Faceでもモデルが公開されています。以下が、Hugging FaceのURLです。

https://huggingface.co/ibm-granite/granite-timeseries-ttm-r2

### Granite時系列モデルの主な特長
•軽量＆柔軟性高:100万パラメータ以下の軽量モデルとなっており、リソースが限られた環境でも高速に動作。
•多様な入出力対応:分単位・時間単位などの細やかな時間粒度、複数ターゲット列をサポート。
•Zero-shot予測対応:公開データ約7億ポイントで事前学習済み、追加学習なしでも良好な予測性能を発揮。

### Granite Time Seriesモデルの詳細

①. 予測に使用するデータセットの量に応じて、3つのパターンのモデルを用意
　•granite-ttm-512-96-r2（512データポイントが必要）
　•granite-ttm-1024-96-r2（1,024データポイントが必要）
　•granite-ttm-1536-96-r2（1,536データポイントが必要）

 512や1024という数字は、学習データで何レコード必要かを意味しています。
 96という数字は、予測する際に何レコード分の予測をするかを意味しています。
 なので、
granite-ttm-512-96-r2は、
512レコードを使って、96レコード分未来の予測をするモデルになります。
 
 
②. watsonx.aiのAPI経由、またはHugging Faceでモデルのダウンロードが可能
③. 分単位から時間単位の粒度の予測をサポート（例: 10分、15分、1時間など）
④. 用途に応じて2つのモードをサポート
　•Zero-shot予測: モデルをそのまま使用して予測値を取得
　•Fine Tuning（Hugging Face経由でのモデルアクセスのみ）: モデルをチューニングして予測値を取得

## 2. 準備
さて、SPSS ModelerでGraniteを使う準備をしていきます。

### ①. 環境情報
今回実装した環境の情報は以下になります。


|ソフトウェア等    |バージョン                |
|----------|--------------------------|
|OS|Windows 11 Pro |
|SPSS Modeler  |18.6 (windows)         |
|Python|3.10.7 (デフォルト)|
|granite tsfm |0.2.23 |
|numpy|**1.26.4** |
|pandas|2.2.3|
|torch|2.6.0|

### ①. ライブラリの導入
今回は、以下のURLにあるサンプルを参考しています。

https://github.com/ibm-granite-community/granite-timeseries-cookbook/blob/main/recipes/Time_Series/Time_Series_Getting_Started.ipynb

まずは、granite-tsfmライブラリを導入します。
結構な数ライブラリが導入されるので、通信環境によっては時間がかかります。

``` :
C:\Program Files\IBM\SPSS\Modeler\18.6\python_venv\Scripts>python -m pip install  "granite-tsfm[notebooks]==0.2.23"
```
また、Pytorchも必要なため、Pytorchも導入します。
※. 私はテキストマイニングの時に導入しているので特に今回は導入していません。

https://qiita.com/harrowharrow16/items/248ff8fe3879b63e7ae3

```
C:\Program Files\IBM\SPSS\Modeler\18.6\python_venv\Scripts>python -m pip install torch torchvision torchaudio
```


※.5/8追記 Fine tuningするときに、transformersも必要なため導入しましょう。
※.私はテキストマイニングの時に導入しているので特に今回は導入していません。
```
C:\Program Files\IBM\SPSS\Modeler\18.6\python_venv\Scripts>python -m pip install transformers
```

### ②. Granite Time Series Modelの使い方
さて、ライブラリを導入したので、簡単にこのモデルの使い方を理解しておきましょう。

#### a. ライブラリ
今回使用するライブラリは、"tsfm_public"です。
その中から、TinyTimeMixerモデル、予測パイプライン、プロット関数を使用します。

```python: tsfm_public
from tsfm_public import (
    TimeSeriesForecastingPipeline, # 時系列予測のパイプライン
    TimeSeriesPreprocessor,        # 入力データの整形・スケーリング
    TinyTimeMixerForPrediction,    # 時系列予測モデル
)
```

#### b. モデルの初期化
Hugging Face Granite Time Seriesは 事前学習済みモデルなので、fine-tuning しなくても使えるのですが、「入力データにあわせて、どう前処理すればよいか」をモデルに教えてあげる作業が必要になります。
それが、TimeSeriesPreprocessorです。

```python: TimeSeriesPreprocessor
# 列の指定
column_specifiers = {
    "timestamp_column": timestamp_column, # 時間
    "id_columns": [],                     # 複数系列を識別するためのID（今回は1系列なので空）
    "target_columns": target_columns,     # 予測対象（"total load actual"）
    "control_columns": [],                # 説明変数（天気とか、曜日などの外部変数）? 今は無し
}

# TimeSeriesPreprocessorインスタンスの作成
tsp = TimeSeriesPreprocessor(
    **column_specifiers,
    context_length=context_length,        #学習に使用するレコード数
    prediction_length=prediction_length,  #予測するレコード数
    scaling=True,                         #データのスケーリングを有効化
    scaler_type="standard",               #標準化（平均0・分散1）を適用
)

#入力データで事前学習
trained_tsp = tsp.train(input_df)
```

trained_tsp = tsp.train(input_df)の処理では、以下が行われています。
1. データのスケーリング（標準化）
　scaler_type="standard" の場合、データの平均と標準偏差を計算し、標準化を適用。

2. 時系列の整形
　context_length や prediction_length に基づいて、学習・予測データのフォーマットを変換。

3. カラムのマッピング
　column_specifiers に基づいて、特徴量やターゲット変数を識別。

#### c.モデルの実行

今回は、事前学習済みのモデルをそのまま使いZero-shot予測をします。
「追加学習せずに使うモデル」という意味の「Zero-shot」から由来しています。
```python: モデル定義
zeroshot_model = TinyTimeMixerForPrediction.from_pretrained(
    "ibm-granite/granite-timeseries-ttm-r2",  # Hugging Face 上の IBMのGraniteシリーズ 時系列モデル（TinyTimeMixer）
    revision="512-96-ft-r2.1",                # "512-96-ft-r2.1" は学習済み重み（revision）で、入力長512・出力長96 に対応したモデル
    num_input_channels=len(target_columns),   # num_input_channels はターゲットの列数。今回は "total load actual" の1列なので 1
)

```

モデルを実行するのに使うデバイスを判断します。
cudaとかAIって感じがしますね(笑)
筆者のPCはもちろん、cpuです。。。NVIDIAさんのGPUは搭載されておりません。。。

```python: デバイス確認
# GPU（CUDA）が使えれば使う、無ければCPU。
device = "cuda" if torch.cuda.is_available() else "cpu"
```


パイプラインを定義します。モデル + 前処理器 + 推論設定 をまとめた便利なインターフェース。
feature_extractor=tsp で、前に train() した前処理器が使われる。

```python:パイプライン定義
pipeline = TimeSeriesForecastingPipeline(
    zeroshot_model,         # 上記で設定したGraniteを指定
    device=device,          # CPU or GPUが指定される
    feature_extractor=tsp,  # 上記で設定したTimeSeriesPreprocessorを指定
    batch_size=512,         # バッチサイズ
    freq="h",               # hは時間の意味
)

```

パイプラインの実行

```python: モデル実行
zeroshot_forecast = pipeline(input_df)
```

戻り値(zeroshot_forecast)は、DataFrame形式で、予測結果が入ってきます。
下の表のような感じです。

Aは予測に使った時系列データです。が、ndarrayに上書きされます。（元データが消える）
A_predictionは予測値です。こちらもndarrayになります。
今回は、96個先まで予測するので、リストには96個入ります。

|time    |A_prediction              | A |
|----------|--------------------------|---|
| 2018-05-14 16:00:00 |29782, 29904, 30401|29422, 28956, 28988|
| 2018-05-14 17:00:00   |29811, 30104, 30893|28956, 28988, 29499|
| 2018-05-14 18:00:00 |29871, 30471, 30949|28988, 29499, 30870|

入力データは、以下のような時系列データでした。
|time    | A |
|----------|--------------------------|
| 2018-05-14 16:00:00 |29598|
| 2018-05-14 17:00:00 |29422|
| 2018-05-14 18:00:00   |28956|
| 2018-05-14 19:00:00 |29499|

モデルの戻り値は未来の値のため、"2018-05-14 16:00:00" の行にある値は、
"2018-05-14 17:00:00"以降の予測値(A_Prediction)と実測値(A)が入っています。
なのでリストの1つ目が、"2018-05-14 17:00:00"のAの予測値と実測値です。２つ目は以降のレコード値。

このような仕様を事前に理解しておきましょう。


#### d.モデル実行補足
Granite Time Series Modelは下の3パターンのモデルがあります。

　•granite-ttm-512-96-r2（512データポイントが必要）
　•granite-ttm-1024-96-r2（1,024データポイントが必要）
　•granite-ttm-1536-96-r2（1,536データポイントが必要）
 
どれも、96レコード先まで予測するものです。
違いは、入力に必要なレコード数が512、1024、1536となっている点です。
それぞれのモデルは入力したデータが必要数に足りない場合は予測ができません。

例えば、"granite-ttm-512-96-r2"を使うときに、1000レコードのデータを入力した場合は
512レコード目までは予測値はでません。
513レコード目から予測値が96レコード先までの分、取得できます。
こういう点も覚えておきましょう。


## 3. まとめ
今回は、SPSS ModelerでGranite Time Series Modelを使う準備及び、モデルの仕様を簡単に説明しました。
次回以降に、このモデルを使ってSPSS Modelerの拡張ノードで時系列予測をしていこうと思います。

次回のゼロショットモデル編です。

https://qiita.com/harrowharrow16/items/6cca1a61ea90cecb7937


# 参考

SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/items/503037195081d3323eee

SPSS Modeler 逆引きストリーム集

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008

SPSS funさん記事集

https://qiita.com/spssfun2017

SPSS連載ブログバックナンバー

https://qiita.com/416nishimaki/items/24c054defbe7280bcf0e

SPSSヒモトクブログ

https://www.ibm.com/blogs/solutions/jp-ja/category/bigdata-analytics/spss-modeler-himotoku/

今後は、ヒモトクブログなどは以下のTechXchangeのコミュニティに統合される予定です。
ご興味がある方は、ぜひiBM IDを登録して参加してみてください！！！お待ちしています。

IBM TechXchange Data Science Japan

https://community.ibm.com/community/user/ai-datascience/communities/community-home?communitykey=5e746c4e-1ae3-4db4-a23c-153cf231fe73