【LLM】Amazon Bedrockで時系列予測を行ってみる

Agaroot IT Partners(AITP)のtomoです。

Amazon Bedrock (以下よりBedrock)が公開されてからそれなりの時間が経ちました。日本語書籍も出版されていますし、多くの方が入門レベルを終えたのではないでしょうか。中には「チャットや要約などよく言われる活用法もいいけれど、他の少し変わった活用ができるかどうか試してみて、大規模言語モデル(LLM)やBedrockにもっと慣れてみたい」という方もいらっしゃるかもしれません。

ということで、今回はBedrockを用いて時系列予測ができないか模索してみます。生成AIと時系列予測の組み合わせで情報を探すとそれなりに出てきますが、Bedrockと時系列予測の組み合わせでは、下記を除いてあまり見受けられない印象を受けます。
https://www.fsi.co.jp/blog/9869/
半分遊び感覚で、少し変わった活用法を模索してBedrockにより慣れていくという意味では時系列予測は打ってつけではないでしょうか。

この記事はこのような方におすすめ

  • BedrockやLangChainの入門はお済みの方(そこまで難しいことは行いませんが、Bedrockの利用方法や実装の説明は省略させていただきます🙏)
  • 生成AIやBedrockを「遊んでいく中で」より慣れていきたい方

今回使うデータセットとタスク

今回試しに使うデータセットはKaggleで公開されている“Daily Climate time series data”です。こちらはインドのデリーにおける、1日ごとの平均気温や湿度といった気象データがCSV形式で公開されています。詳細はリンク先をご参照ください。

今回のタスクではこのデータセットのうち、学習データ(2013~2016年の気象データ)をLLMに読み込ませたのち、2017年の1日ごとの平均気温を予測させます。

今回使うモデル

利用するモデルは最大トークンも大きく、専門性の高いタスクもこなせるClaude 3 Opusを利用します。

高性能な分利用料金は他モデルより高めなので、その点はご注意ください。正確な料金体系は下記をご参照いただきたいのですが、参考までに今回のブログ執筆(おそらく数十回はコードを実行しました)でかかった料金をお伝えすると$10.18となっています。
https://aws.amazon.com/jp/bedrock/pricing/

また、このモデルは現在バージニア北部とオレゴンでのみ利用可能です。モデルアクセスのリクエストやソースコードの実行はそちらのリージョンで行ってください。

いざ実行

以下の順番に従って試してみて下さい。

ライブラリのインストール

以下コマンドによりライブラリをインストールしてください。

$ pip install langchain langchain-community boto3 langchain-aws

ソースコード

以下ソースコードを記述して下さい。

from langchain_aws import ChatBedrock
from langchain_core.prompts import PromptTemplate

llm = ChatBedrock(model_id="us.anthropic.claude-3-opus-20240229-v1:0",
                  temperature=1)

# 長いのでデータを省略
train = """
date,meantemp,humidity,wind_speed,meanpressure
2013-01-01,10.0,84.5,0.0,1015.6666666666666
2013-01-02,7.4,92.0,2.98,1017.8
2013-01-03,7.166666666666667,87.0,4.633333333333334,1018.6666666666666
2013-01-04,8.666666666666666,71.33333333333333,1.2333333333333334,1017.1666666666666
2013-01-05,6.0,86.83333333333333,3.6999999999999997,1016.5
2016-12-31,15.052631578947368,87.0,7.325,1016.1
"""

target = "meantemp"

description = """
## Content
The Dataset is fully dedicated for the developers who want to train the model on Weather Forecasting for Indian climate. This dataset provides data from 1st January 2013 to 24th April 2017 in the city of Delhi, India. The 4 parameters here are
meantemp, humidity, wind_speed, meanpressure.
## columns
- date: Date of format YYYY-MM-DD
- meantemp: Mean temperature averaged out from multiple 3 hour intervals in a day.
- humidity: Humidity value for the day (units are grams of water vapor per cubic meter volume of air).
- wind_speed: Wind speed measured in kmph.
- meanpressure: Pressure reading of weather (measure in atm)
"""

template = """
あなたは時系列予測を行うデータ分析者です。
<train>に記載されたCSVデータを元に、未知の時系列データを推測します。
2017-01-01~2017-04-24の各日付について、<target>に記載された列がどのような値になるのか予測して下さい。
<example>のように、日付(date)、推測値(answer)のみを各行ごとに返却して下さい。<example>のようなCSV以外は一切メッセージに含まないでください。
推測値は小数第3位を四捨五入し、小数第2位までにしてください。四捨五入した後の小数部分が.00であれば小数点以降を記載せず、整数部分のみ返却してください。
適宜、<description>に記載されたデータの説明を参照して下さい。
<train>
{train}
</train>
<target>
{target}
</target>
<description>
{description}
</description>
<example>
date,answer
2017-01-01,10.2
2017-01-02,11
2017-01-03,10.58
</example>
"""
prompt = PromptTemplate.from_template(template)
llm_chain = prompt | llm

result = llm_chain.invoke({
    "train": train,
    "target": target,
    "description": description,
})
print(result.content)

少し解説🤏

ツールなどを使わなかった理由

本当はLLM Math(AIエージェントにPythonコードを書かせて実行することで正確に計算処理を行わせる、Langchainのツール)を用いて、AIエージェントに本格的にデータ分析を行わせたり、線形モデルや決定木モデルの作成などもさせてみたかったのですが、そこまですると後述する最大アウトプットの上限などが起因して上手くいきませんでした。
ということで已む無くそういった試みは行わず、プロンプトのみで対応しました。

temperatureについて

モデルを定義する際、temperatureを0にすると同じ推測値ばかりが並ぶようになりました。前日の値や同月の平均値などを過大評価したのかもしれません。1に近づけていくとその傾向が弱まっていきます。

もう少しtemperatureのチューニングを行えばより良い精度で予測が行えるかもしれません。

コードの実行

python3 time-series.pyを実行し、結果を確認してみて下さい。
ちなみに私が実行した時にはこのような結果となりました。

date,answer
2017-01-01,15.17
2017-01-02,14.41
2017-01-03,15.97
2017-01-04,15.41
2017-01-05,18.78
2017-01-06,18.54
2017-01-07,16.97
2017-01-08,17.15
2017-01-09,17.51
2017-01-10,16.31
2017-01-11,16.03
2017-01-12,15.94
2017-01-13,16.32
2017-01-14,19.64
2017-01-15,19.38
2017-01-16,18.73
2017-01-17,15.95
2017-01-18,14.92
2017-01-19,15.23
2017-01-20,14.96
2017-01-21,13.12
2017-01-22,12.39
2017-01-23,14.62
2017-01-24,14.64
2017-01-25,16.34
2017-01-26,15.71
2017-01-27,18.24
2017-01-28,18.8
2017-01-29,19.39
2017-01-30,18.84
2017-01-31,18.44
2017-02-01,18.25
2017-02-02,17
2017-02-03,16.9
2017-02-04,15.92
2017-02-05,16.83
2017-02-06,16.62
2017-02-07,16.26
2017-02-08,16.78
2017-02-09,18.2
2017-02-10,17.66
2017-02-11,17.11
2017-02-12,18.27
2017-02-13,17.69
2017-02-14,19.71
2017-02-15,20.77
2017-02-16,20.92
2017-02-17,17.39
2017-02-18,17.45
2017-02-19,20.27
2017-02-20,21.19
2017-02-21,21.75
2017-02-22,21.88
2017-02-23,18.59
2017-02-24,18.37
2017-02-25,19.9
2017-02-26,20.39
2017-02-27,21.21
2017-02-28,21.4
2017-03-01,21.72
2017-03-02,21
2017-03-03,22.27
2017-03-04,23.29
2017-03-05,22.43
2017-03-06,21.58
2017-03-07,21.74
2017-03-08,23.45
2017-03-09,24.91
2017-03-10,23.91
2017-03-11,23.38
2017-03-12,23.17
2017-03-13,22
2017-03-14,21.47
2017-03-15,20.92
2017-03-16,23.65
2017-03-17,26.73
2017-03-18,26.57
2017-03-19,25.71
2017-03-20,26.05
2017-03-21,25.86
2017-03-22,26.51
2017-03-23,27.83
2017-03-24,30.16
2017-03-25,29.9
2017-03-26,27.7
2017-03-27,27.68
2017-03-28,27.2
2017-03-29,28.67
2017-03-30,29.19
2017-03-31,27.83
2017-04-01,28.82
2017-04-02,28.68
2017-04-03,29.07
2017-

93日分の予測結果を取れました。
Claude 3 Opusの最大アウトプットは4096トークンなので、すべての日付の予測が取得できるとは限らないのでご注意ください。
https://docs.anthropic.com/en/docs/about-claude/models

(オプション) 精度の評価

予測結果の取得は上記までで完結しましたが、よければ精度がどこまで高いかどうか(≒LLMの予測をどこまで信頼していいかどうか)確かめてみたいと思います。

評価指標

取得できた予測値の精度を評価するため、まずはその指標を決めます。

今回は、時系列予測を含めた数値予測の指標として多用されるMSE(Mean Squared Error)/MAE(Mean Absolute Error)/R-Squaredを用いることにしました。

各指標の説明は少し専門的な話になる(そして正確にわかりやすくできるか怪しい💦)ので本記事では省略させていただきますが、よければこちらをご参照ください。
https://datawokagaku.com/reg_metrics/

ライブラリのインストール

評価指標を計算するために必要なライブラリを下記コマンドにて取得して下さい。

$ pip install scikit-learn

ソースコード

以下コードにより各評価指標の計算が行えます。python3 evaluate.pyを実行して下さい。

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

# test/predどちらとも長いので省略 配列の長さは統一して下さい
test = [    
    15.91304347826090,
    18.5,
    17.11111111111110,
    18.7,
    18.38888888888890,
    
]
pred = [
    15.17,
    14.41,
    15.97,
    15.41,
    18.78,
]

mse = mean_squared_error(test, pred)
rae = mean_absolute_error(test, pred)
r2 = r2_score(test, pred)

print(f"MSE(Mean Squared Error): {mse}")
print(f"MAE(Mean Absolute Error): {rae}")
print(f"R-Squared: {r2}")

私の実行結果は下記のとおりでした。

MSE(Mean Squared Error): 7.849302145659115
MAE(Mean Absolute Error): 2.3614972561080765
R-Squared: 0.6858991384645903

MSE(Mean Squared Error)やMAE(Mean Absolute Error)を鑑みると、大体 2~3度(恐らく摂氏)程度の誤差がある、といったところでしょうか。数ヶ月間分の予測結果としては悪くないかもしれません(?)

まとめ

今回はBedrockのClaude 3 Opusを利用して時系列予測を行ってみました。temperatureを1にしたこともあり、必ず今回のように行くとは限りませんが、意外と悪くない結果になり私自身少し驚いています。

とはいえ、生成AIを用いない従来の時系列予測との比較などはできていませんので、もしかしたらそちらに比べると精度が劣るかもしれません。また今回は気象データでしたが、他の時系列データに対してどの程度効果があるのか不明です。

今回の内容はあくまでも簡単な検証として、参考程度に捉えて下さい。
よければ皆様も色々試してみて、予測精度の改善などに挑戦していただければと思います👋

関連するタグ