1. 导入包

首先,我们导入所需的包并初始化 Nixtla 客户端

import pandas as pd
from nixtla import NixtlaClient
from utilsforecast.losses import rmse
from utilsforecast.evaluation import evaluate
nixtla_client = NixtlaClient(
    # defaults to os.environ["NIXTLA_API_KEY"]
    api_key = 'my_api_key_provided_by_nixtla'
)

2. 加载数据

df = pd.read_parquet('https://datasets-nixtla.s3.amazonaws.com/m4-hourly.parquet')

h = 48
valid = df.groupby('unique_id', observed=True).tail(h)
train = df.drop(valid.index)
train.head()
unique_iddsy
0H11605.0
1H12586.0
2H13586.0
3H14559.0
4H15511.0

3. 零样本预测

我们可以尝试不进行任何微调来查看 TimeGPT 的表现如何。

fcst_kwargs = {'df': train, 'freq': 1, 'model': 'timegpt-1-long-horizon'}
fcst = nixtla_client.forecast(h=h, **fcst_kwargs)
zero_shot_eval = evaluate(fcst.merge(valid), metrics=[rmse], agg_fn='mean')
zero_shot_eval
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Querying model metadata...
WARNING:nixtla.nixtla_client:The specified horizon "h" exceeds the model horizon, this may lead to less accurate forecasts. Please consider using a smaller horizon.
INFO:nixtla.nixtla_client:Restricting input...
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
metricTimeGPT
0rmse1504.474342

4. 微调

现在我们可以对 TimeGPT 进行一些微调,并将模型保存供以后使用。我们可以通过提供 output_model_id 来定义我们希望该模型拥有的 ID。

first_model_id = 'my-first-finetuned-model'
nixtla_client.finetune(output_model_id=first_model_id, **fcst_kwargs)
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Calling Fine-tune Endpoint...
'my-first-finetuned-model'

现在我们可以通过 finetuned_model_id 参数提供其 ID 来使用这个微调模型进行预测。

first_finetune_fcst = nixtla_client.forecast(h=h, finetuned_model_id=first_model_id, **fcst_kwargs)
first_finetune_eval = evaluate(first_finetune_fcst.merge(valid), metrics=[rmse], agg_fn='mean')
zero_shot_eval.merge(first_finetune_eval, on=['metric'], suffixes=('_zero_shot', '_first_finetune'))
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
WARNING:nixtla.nixtla_client:The specified horizon "h" exceeds the model horizon, this may lead to less accurate forecasts. Please consider using a smaller horizon.
INFO:nixtla.nixtla_client:Restricting input...
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
metricTimeGPT_zero_shotTimeGPT_first_finetune
0rmse1504.4743421472.024619

我们可以看到误差减小了。

5. 进一步微调

现在我们可以使用 NixtlaClient.finetune 方法将此模型进一步微调,通过将我们已经微调过的模型作为 finetuned_model_id 提供,它将在此模型基础上进行更多微调。我们还可以更改微调设置,例如使用 finetune_depth=3

second_model_id = nixtla_client.finetune(finetuned_model_id=first_model_id, finetune_depth=3, **fcst_kwargs)
second_model_id
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
INFO:nixtla.nixtla_client:Calling Fine-tune Endpoint...
'468b13fb-4b26-447a-bd87-87a64b50d913'

由于这次我们没有提供 output_model_id,它被分配了一个 UUID。

现在我们可以使用此模型进行预测。

second_finetune_fcst = nixtla_client.forecast(h=h, finetuned_model_id=second_model_id, **fcst_kwargs)
second_finetune_eval = evaluate(second_finetune_fcst.merge(valid), metrics=[rmse], agg_fn='mean')
first_finetune_eval.merge(second_finetune_eval, on=['metric'], suffixes=('_first_finetune', '_second_finetune'))
INFO:nixtla.nixtla_client:Validating inputs...
INFO:nixtla.nixtla_client:Preprocessing dataframes...
WARNING:nixtla.nixtla_client:The specified horizon "h" exceeds the model horizon, this may lead to less accurate forecasts. Please consider using a smaller horizon.
INFO:nixtla.nixtla_client:Restricting input...
INFO:nixtla.nixtla_client:Calling Forecast Endpoint...
metricTimeGPT_first_finetuneTimeGPT_second_finetune
0rmse1472.0246191435.365211

我们可以看到误差又减小了一些。

6. 列出微调模型

我们可以使用 NixtlaClient.finetuned_models 方法列出我们的微调模型。

finetuned_models = nixtla_client.finetuned_models()
finetuned_models
[FinetunedModel(id='468b13fb-4b26-447a-bd87-87a64b50d913', created_at=datetime.datetime(2024, 12, 30, 17, 57, 31, 241455, tzinfo=TzInfo(UTC)), created_by='user', base_model_id='my-first-finetuned-model', steps=10, depth=3, loss='default', model='timegpt-1-long-horizon', freq='MS'),
 FinetunedModel(id='my-first-finetuned-model', created_at=datetime.datetime(2024, 12, 30, 17, 57, 16, 978907, tzinfo=TzInfo(UTC)), created_by='user', base_model_id='None', steps=10, depth=1, loss='default', model='timegpt-1-long-horizon', freq='MS')]

虽然这种表示方式可能对编程有用,但在探索性设置中,将其显示为 dataframe 更直观,我们可以通过提供 as_df=True 来实现。

nixtla_client.finetuned_models(as_df=True)
idcreated_atcreated_bybase_model_idstepsdepthlossmodelfreq
0468b13fb-4b26-447a-bd87-87a64b50d9132024-12-30 17:57:31.241455+00:00usermy-first-finetuned-model103defaulttimegpt-1-long-horizonMS
1my-first-finetuned-model2024-12-30 17:57:16.978907+00:00userNone101defaulttimegpt-1-long-horizonMS

我们可以看到,第二个模型的 base_model_id 是我们的第一个模型,以及其他元数据。

7. 删除微调模型

为了保持整洁,并且由于微调模型的数量限制为 50 个,您可以删除不太有前景的模型,以便为更多实验腾出空间。例如,我们可以删除我们的第一个微调模型。请注意,即使它被用作我们第二个模型的基础,它们也是独立保存的,因此删除它不会影响我们的第二个模型,只会影响相关的元数据。

nixtla_client.delete_finetuned_model(first_model_id)
True

我们可以验证我们的第一个模型不再显示在我们可用的模型列表中。

nixtla_client.finetuned_models(as_df=True)
idcreated_atcreated_bybase_model_idstepsdepthlossmodelfreq
0468b13fb-4b26-447a-bd87-87a64b50d9132024-12-30 17:57:31.241455+00:00usermy-first-finetuned-model103defaulttimegpt-1-long-horizonMS