初めに
過去に 比較的小さい時系列基盤モデルを触りました。こちらはfine tuingはできなかったので、fine tuingができてより大きいモデルを触っていきます
環境
- L4 GPU
- ubuntu22.04
- jupter notebook
ライブラリのインストール
# library install
!pip install git+https://github.com/amazon-science/chronos-forecasting.git
データの取得と分析
以下でデータを取得・分析をしていきます
import pandas as pd # データ読み込み # https://github.com/zhouhaoyi/ETDataset/blob/main/ETT-small/ETTh1.csv df = pd.read_csv("ETTh1.csv") print(len(df)) df.head(2)
以下のようにデータの中が表示されます
データ形式の変換
推論に用いれる形に変換をします
import torch context_length = 512 forecast_horizon = 96 # データセット分割 df_train = df.iloc[-(context_length+forecast_horizon):-forecast_horizon] df_test = df.iloc[-forecast_horizon:] # 形式の変更 train_tensor = torch.tensor(df_train[["HUFL", "HULL", "MUFL", "MULL", "LUFL", "LULL", "OT"]].values, dtype=torch.float) train_tensor = train_tensor.t() test_tensor = torch.tensor(df_test[["HUFL", "HULL", "MUFL", "MULL", "LUFL", "LULL", "OT"]].values, dtype=torch.float) test_tensor = test_tensor.t()
推論
モデルのロード
以下でモデルをロードします
import pandas as pd import torch from chronos import ChronosPipeline pipeline = ChronosPipeline.from_pretrained( "amazon/chronos-t5-large", device_map="cuda", # use "cpu" for CPU inference and "mps" for Apple Silicon torch_dtype=torch.bfloat16, )
推論実行及びグラフにプロット
forecast = pipeline.predict(train_tensor, forecast_horizon, limit_prediction_length=False) forecast_median_tensor, _ = torch.median(forecast, dim=1) import matplotlib.pyplot as plt channel_idx = 6 time_index = 0 history = train_tensor[channel_idx, :].detach().numpy() true = test_tensor[channel_idx, :].detach().numpy() pred = forecast_median_tensor[channel_idx, :].detach().numpy() plt.figure(figsize=(12, 4)) # Plotting the first time series from history plt.plot(range(len(history)), history, label='History (512 timesteps)', c='darkblue') # Plotting ground truth and prediction num_forecasts = len(true) offset = len(history) plt.plot(range(offset, offset + len(true)), true, label='Ground Truth (96 timesteps)', color='darkblue', linestyle='--', alpha=0.5) plt.plot(range(offset, offset + len(pred)), pred, label='Forecast (96 timesteps)', color='red', linestyle='--') plt.title(f"ETTh1 (Hourly) -- (idx={time_index}, channel={channel_idx})", fontsize=18) plt.xlabel('Time', fontsize=14) plt.ylabel('Value', fontsize=14) plt.legend(fontsize=14) plt.show()
以下のようにゼロショットで推論ができました。かなり一致しています
fine tuing
ライブラリのインストール
!pip install "chronos[training] @ git+https://github.com/amazon-science/chronos-forecasting.git" !git clone https://github.com/amazon-science/chronos-forecasting.git # Clone the ibm/tsfm ! git clone https://github.com/IBM/tsfm.git # Change directory. Move inside the tsfm repo. %cd tsfm # Install the tsfm library ! pip install ".[notebooks]"
学習用のデータの変換
from pathlib import Path from typing import List, Optional, Union import numpy as np from gluonts.dataset.arrow import ArrowWriter from pathlib import Path from typing import List, Optional, Union import numpy as np from gluonts.dataset.arrow import ArrowWriter def convert_to_arrow( path: Union[str, Path], time_series: Union[List[np.ndarray], np.ndarray], start_times: Optional[Union[List[np.datetime64], np.ndarray]] = None, compression: str = "lz4", ): if start_times is None: # Set an arbitrary start time start_times = [np.datetime64("2000-01-01 00:00", "s")] * len(time_series) assert len(time_series) == len(start_times) dataset = [ {"start": start, "target": ts} for ts, start in zip(time_series, start_times) ] ArrowWriter(compression=compression).write_to_file( dataset, path=path, ) # Convert to GluonTS arrow format cols = ["HUFL", "HULL", "MUFL", "MULL", "LUFL", "LULL", "OT"] convert_to_arrow( path = "./etth1-train.arrow", time_series=[np.array(df_train[col]) for col in cols], start_times=[pd.to_datetime(df_train["date"]).values[0]] * len(cols), )
以下のようなファイルが生成されます
参考サイト
fine tuing
以下で追加学習をします
import yaml batch_size = 2 # バッチサイズ num_steps = train_size/batch_size print("steps:" + str(num_steps)) # Fine Tuningの設定 config_data = { 'training_data_paths': ["./etth1-train.arrow"], # 学習データファイルのパス 'probability': [1.0], 'output_dir': './output/', # 学習結果の出力ディレクトリ 'context_length': context_length, 'prediction_length': forecast_horizon, 'max_steps': num_steps, 'per_device_train_batch_size': batch_size, 'learning_rate': 0.001, 'model_id': 'amazon/chronos-t5-large', # 'model_id': 'amazon/chronos-t5-base', 'random_init': False, # 事前学習済みモデルを使用 'tf32': True, # NVIDIA GPUの場合Trueにする 'gradient_accumulation_steps':2, } # 設定ファイルをYAML形式で保存 config_file_path = './ft_config.yaml' with open(config_file_path, 'w') as file: yaml.dump(config_data, file) def fine_tune_chronos(train_file_path, config_file_path): """ chronos-t5モデルをFine Tuningする関数 Args: train_file_path (str): 学習用データファイルのパス config_file_path (str): Fine Tuning設定ファイルのパス """ # Fine Tuningの実行 !CUDA_VISIBLE_DEVICES=0 python chronos-forecasting/scripts/training/train.py --config {config_file_path} # Fine Tuningの実行 fine_tune_chronos("./etth1-train.arrow", config_file_path)
ログは以下のようになりました
{'loss': 3.8517, 'grad_norm': 1.0407471656799316, 'learning_rate': 0.0009282433983926521, 'epoch': 0.07} {'loss': 3.7261, 'grad_norm': 0.7981559038162231, 'learning_rate': 0.0008564867967853042, 'epoch': 0.14} {'loss': 3.6565, 'grad_norm': 1.0834617614746094, 'learning_rate': 0.0007847301951779565, 'epoch': 0.22} {'loss': 3.5609, 'grad_norm': 0.6380050182342529, 'learning_rate': 0.0007129735935706086, 'epoch': 0.29} {'loss': 3.4786, 'grad_norm': 1.107723355293274, 'learning_rate': 0.0006412169919632607, 'epoch': 0.36} {'loss': 3.3614, 'grad_norm': 0.8139169812202454, 'learning_rate': 0.0005694603903559128, 'epoch': 0.43} {'loss': 3.2374, 'grad_norm': 0.9819308519363403, 'learning_rate': 0.0004977037887485649, 'epoch': 0.5} {'loss': 3.1432, 'grad_norm': 1.3025404214859009, 'learning_rate': 0.000425947187141217, 'epoch': 0.57} {'loss': 3.0098, 'grad_norm': 1.464908242225647, 'learning_rate': 0.0003541905855338691, 'epoch': 0.65} {'loss': 2.8967, 'grad_norm': 1.4902337789535522, 'learning_rate': 0.00028243398392652127, 'epoch': 0.72} {'loss': 2.7994, 'grad_norm': 1.2662851810455322, 'learning_rate': 0.00021067738231917335, 'epoch': 0.79} {'loss': 2.7279, 'grad_norm': 1.741388201713562, 'learning_rate': 0.0001389207807118255, 'epoch': 0.86} {'loss': 2.6553, 'grad_norm': 1.594014286994934, 'learning_rate': 6.716417910447761e-05, 'epoch': 0.93} {'train_runtime': 7191.7126, 'train_samples_per_second': 3.876, 'train_steps_per_second': 0.969, 'train_loss': 3.195165220275949, 'epoch': 1.0} 100%|█████████████████████████████████████| 6968/6968 [1:59:51<00:00, 1.03s/it]
追加学習モデルを使った推論
from chronos import ChronosPipeline import matplotlib.pyplot as plt def predict_with_chronos(train_tensor, forecast_horizon, model_name="amazon/chronos-t5-large", device_map="cuda"): """ chronos-t5モデルで予測を行う関数 Args: train_tensor (torch.Tensor): 学習用データテンソル forecast_horizon (int): 予測する長さ model_name (str): モデル名 (デフォルト: "amazon/chronos-t5-large") device_map (str): デバイス ("cuda" or "cpu") Returns: forecast_median_tensor (torch.Tensor): 予測結果の中央値テンソル """ pipeline = ChronosPipeline.from_pretrained( model_name, device_map=device_map, torch_dtype=torch.bfloat16, # 計算精度を指定 ) # 予測の実行 (limit_prediction_length=Falseで予測長を制限しない) forecast = pipeline.predict(train_tensor, forecast_horizon, limit_prediction_length=False) forecast_median_tensor, _ = torch.median(forecast, dim=1) # 予測結果の中央値を計算 return forecast_median_tensor, forecast def visualize_prediction(train_tensor, test_tensor, forecast_median_tensor, channel_idx=6): """ 予測結果を可視化する関数 Args: train_tensor (torch.Tensor): 学習用データテンソル test_tensor (torch.Tensor): テスト用データテンソル forecast_median_tensor (torch.Tensor): 予測結果の中央値テンソル channel_idx (int): 可視化するチャンネルのインデックス (デフォルト: 6, OT) """ history = train_tensor[channel_idx, :].detach().numpy() # 学習用データ true = test_tensor[channel_idx, :].detach().numpy() # 実測値 pred = forecast_median_tensor[channel_idx, :].detach().numpy() # 予測値 plt.figure(figsize=(12, 4)) plt.plot(range(len(history)), history, label='History (512 timesteps)', c='darkblue') plt.plot(range(len(history), len(history) + len(true)), true, label='Ground Truth (96 timesteps)', color='darkblue', linestyle='--', alpha=0.5) plt.plot(range(len(history), len(history) + len(pred)), pred, label='Forecast (96 timesteps)', color='red', linestyle='--') plt.title(f"ETTh1 (Hourly) - Channel {channel_idx}", fontsize=18) plt.xlabel('Time', fontsize=14) plt.ylabel('Value', fontsize=14) plt.legend(fontsize=14) plt.show() # Fine Tuning後のモデルで予測 forecast_median_tensor_ft, forecast_ft = predict_with_chronos(train_tensor, forecast_horizon=forecast_horizon, model_name="./output/run-4/checkpoint-final/") # 予測結果の可視化 (Fine Tuning後) visualize_prediction(train_tensor, test_tensor, forecast_median_tensor_ft)