18 KiB
18 KiB
In [1]:
import os
os.environ['XLA_PYTHON_CLIENT_PREALLOCATE'] = 'false'
os.environ['JAX_PMAP_USE_TENSORSTORE'] = 'false'In [ ]:
import timesfm
import gc
import numpy as np
import pandas as pd
from timesfm import patched_decoder
from timesfm import data_loaderIn [3]:
from tqdm import tqdm
import dataclasses
import IPython
import IPython.display
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['figure.figsize'] = (8, 6)
mpl.rcParams['axes.grid'] = FalseIn [ ]:
timesfm_backend = "gpu" # @param
tfm = timesfm.TimesFm(
hparams=timesfm.TimesFmHparams(
backend=timesfm_backend,
per_core_batch_size=32,
horizon_len=128,
num_layers=50,
# Se this to True for v1.0 checkpoints
use_positional_embedding=False,
# Note that we could set this to as high as 2048 but keeping it 512 here so that
# both v1.0 and 2.0 checkpoints work
context_len=512,
),
checkpoint=timesfm.TimesFmCheckpoint(
huggingface_repo_id="google/timesfm-2.0-500m-jax"),
)In [5]:
DATA_DICT = {
"ettm2": {
"boundaries": [34560, 46080, 57600],
"data_path": "../datasets/ETT-small/ETTm2.csv",
"freq": "15min",
},
"ettm1": {
"boundaries": [34560, 46080, 57600],
"data_path": "../datasets/ETT-small/ETTm1.csv",
"freq": "15min",
},
"etth2": {
"boundaries": [8640, 11520, 14400],
"data_path": "../datasets/ETT-small/ETTh2.csv",
"freq": "H",
},
"etth1": {
"boundaries": [8640, 11520, 14400],
"data_path": "../datasets/ETT-small/ETTh1.csv",
"freq": "H",
},
"elec": {
"boundaries": [18413, 21044, 26304],
"data_path": "../datasets/electricity/electricity.csv",
"freq": "H",
},
"traffic": {
"boundaries": [12280, 14036, 17544],
"data_path": "../datasets/traffic/traffic.csv",
"freq": "H",
},
"weather": {
"boundaries": [36887, 42157, 52696],
"data_path": "../datasets/weather/weather.csv",
"freq": "10min",
},
}In [6]:
dataset = "ettm1"
data_path = DATA_DICT[dataset]["data_path"]
freq = DATA_DICT[dataset]["freq"]
int_freq = timesfm.freq_map(freq)
boundaries = DATA_DICT[dataset]["boundaries"]
data_df = pd.read_csv(open(data_path, "r"))
ts_cols = [col for col in data_df.columns if col != "date"]
num_cov_cols = None
cat_cov_cols = None
context_len = 512
pred_len = 96
num_ts = len(ts_cols)
batch_size = 8
dtl = data_loader.TimeSeriesdata(
data_path=data_path,
datetime_col="date",
num_cov_cols=num_cov_cols,
cat_cov_cols=cat_cov_cols,
ts_cols=np.array(ts_cols),
train_range=[0, boundaries[0]],
val_range=[boundaries[0], boundaries[1]],
test_range=[boundaries[1], boundaries[2]],
hist_len=context_len,
pred_len=pred_len,
batch_size=num_ts,
freq=freq,
normalize=True,
epoch_len=None,
holiday=False,
permute=True,
)In [ ]:
train_batches = dtl.tf_dataset(mode="train", shift=1).batch(batch_size)
val_batches = dtl.tf_dataset(mode="val", shift=pred_len)
test_batches = dtl.tf_dataset(mode="test", shift=pred_len)In [ ]:
for tbatch in tqdm(train_batches.as_numpy_iterator()):
break
print(tbatch[0].shape)In [ ]:
mae_losses = []
for batch in tqdm(test_batches.as_numpy_iterator()):
past = batch[0]
actuals = batch[3]
forecasts, _ = tfm.forecast(list(past), [0] * past.shape[0], normalize=True)
forecasts = forecasts[:, 0 : actuals.shape[1]]
mae_losses.append(np.abs(forecasts - actuals).mean())
print(f"MAE: {np.mean(mae_losses)}")In [9]:
import jax
from jax import numpy as jnp
from praxis import pax_fiddle
from praxis import py_utils
from praxis import pytypes
from praxis import base_model
from praxis import optimizers
from praxis import schedules
from praxis import base_hyperparams
from praxis import base_layer
from paxml import tasks_lib
from paxml import trainer_lib
from paxml import checkpoints
from paxml import learners
from paxml import partitioning
from paxml import checkpoint_typesIn [10]:
# PAX shortcuts
NestedMap = py_utils.NestedMap
WeightInit = base_layer.WeightInit
WeightHParams = base_layer.WeightHParams
InstantiableParams = py_utils.InstantiableParams
JTensor = pytypes.JTensor
NpTensor = pytypes.NpTensor
WeightedScalars = pytypes.WeightedScalars
instantiate = base_hyperparams.instantiate
LayerTpl = pax_fiddle.Config[base_layer.BaseLayer]
AuxLossStruct = base_layer.AuxLossStruct
AUX_LOSS = base_layer.AUX_LOSS
template_field = base_layer.template_field
# Standard prng key names
PARAMS = base_layer.PARAMS
RANDOM = base_layer.RANDOM
key = jax.random.PRNGKey(seed=1234)In [11]:
model = pax_fiddle.Config(
patched_decoder.PatchedDecoderFinetuneModel,
name='patched_decoder_finetune',
core_layer_tpl=tfm.model_p,
)In [12]:
@pax_fiddle.auto_config
def build_learner() -> learners.Learner:
return pax_fiddle.Config(
learners.Learner,
name='learner',
loss_name='avg_qloss',
optimizer=optimizers.Adam(
epsilon=1e-7,
clip_threshold=1e2,
learning_rate=1e-2,
lr_schedule=pax_fiddle.Config(
schedules.Cosine,
initial_value=1e-3,
final_value=1e-4,
total_steps=40000,
),
ema_decay=0.9999,
),
# Linear probing i.e we hold the transformer layers fixed.
bprop_variable_exclusion=['.*/stacked_transformer_layer/.*'],
)In [13]:
task_p = tasks_lib.SingleTask(
name='ts-learn',
model=model,
train=tasks_lib.SingleTask.Train(
learner=build_learner(),
),
)In [ ]:
task_p.model.ici_mesh_shape = [1, 1, 1]
task_p.model.mesh_axis_names = ['replica', 'data', 'mdl']
DEVICES = np.array(jax.devices()).reshape([1, 1, 1])
MESH = jax.sharding.Mesh(DEVICES, ['replica', 'data', 'mdl'])
num_devices = jax.local_device_count()
print(f'num_devices: {num_devices}')
print(f'device kind: {jax.local_devices()[0].device_kind}')In [ ]:
jax_task = task_p
key, init_key = jax.random.split(key)
# To correctly prepare a batch of data for model initialization (now that shape
# inference is merged), we take one devices*batch_size tensor tuple of data,
# slice out just one batch, then run the prepare_input_batch function over it.
def process_train_batch(batch):
past_ts = batch[0].reshape(batch_size * num_ts, -1)
actual_ts = batch[3].reshape(batch_size * num_ts, -1)
return NestedMap(input_ts=past_ts, actual_ts=actual_ts)
def process_eval_batch(batch):
past_ts = batch[0]
actual_ts = batch[3]
return NestedMap(input_ts=past_ts, actual_ts=actual_ts)
jax_model_states, _ = trainer_lib.initialize_model_state(
jax_task,
init_key,
process_train_batch(tbatch),
checkpoint_type=checkpoint_types.CheckpointType.GDA,
)In [ ]:
jax_model_states.mdl_vars['params']['core_layer'] = tfm._train_state.mdl_vars['params']
jax_vars = jax_model_states.mdl_vars
gc.collect()In [19]:
jax_task = task_p
def train_step(states, prng_key, inputs):
return trainer_lib.train_step_single_learner(
jax_task, states, prng_key, inputs
)
def eval_step(states, prng_key, inputs):
states = states.to_eval_state()
return trainer_lib.eval_step_single_learner(
jax_task, states, prng_key, inputs
)
key, train_key, eval_key = jax.random.split(key, 3)
train_prng_seed = jax.random.split(train_key, num=jax.local_device_count())
eval_prng_seed = jax.random.split(eval_key, num=jax.local_device_count())
p_train_step = jax.pmap(train_step, axis_name='batch')
p_eval_step = jax.pmap(eval_step, axis_name='batch')In [20]:
replicated_jax_states = trainer_lib.replicate_model_state(jax_model_states)
replicated_jax_vars = replicated_jax_states.mdl_varsIn [21]:
best_eval_loss = 1e7
step_count = 0
patience = 0
NUM_EPOCHS = 100
PATIENCE = 5
TRAIN_STEPS_PER_EVAL = 1000
CHECKPOINT_DIR='/home/senrajat_google_com/ettm1_finetune'In [22]:
def reshape_batch_for_pmap(batch, num_devices):
def _reshape(input_tensor):
bsize = input_tensor.shape[0]
residual_shape = list(input_tensor.shape[1:])
nbsize = bsize // num_devices
return jnp.reshape(input_tensor, [num_devices, nbsize] + residual_shape)
return jax.tree.map(_reshape, batch)In [ ]:
for epoch in range(NUM_EPOCHS):
print(f"__________________Epoch: {epoch}__________________", flush=True)
train_its = train_batches.as_numpy_iterator()
if patience >= PATIENCE:
print("Early stopping.", flush=True)
break
for batch in tqdm(train_its):
train_losses = []
if patience >= PATIENCE:
print("Early stopping.", flush=True)
break
tbatch = process_train_batch(batch)
tbatch = reshape_batch_for_pmap(tbatch, num_devices)
replicated_jax_states, step_fun_out = p_train_step(
replicated_jax_states, train_prng_seed, tbatch
)
train_losses.append(step_fun_out.loss[0])
if step_count % TRAIN_STEPS_PER_EVAL == 0:
print(
f"Train loss at step {step_count}: {np.mean(train_losses)}",
flush=True,
)
train_losses = []
print("Starting eval.", flush=True)
val_its = val_batches.as_numpy_iterator()
eval_losses = []
for ev_batch in tqdm(val_its):
ebatch = process_eval_batch(ev_batch)
ebatch = reshape_batch_for_pmap(ebatch, num_devices)
_, step_fun_out = p_eval_step(
replicated_jax_states, eval_prng_seed, ebatch
)
eval_losses.append(step_fun_out.loss[0])
mean_loss = np.mean(eval_losses)
print(f"Eval loss at step {step_count}: {mean_loss}", flush=True)
if mean_loss < best_eval_loss or np.isnan(mean_loss):
best_eval_loss = mean_loss
print("Saving checkpoint.")
jax_state_for_saving = py_utils.maybe_unreplicate_for_fully_replicated(
replicated_jax_states
)
checkpoints.save_checkpoint(
jax_state_for_saving, CHECKPOINT_DIR, overwrite=True
)
patience = 0
del jax_state_for_saving
gc.collect()
else:
patience += 1
print(f"patience: {patience}")
step_count += 1In [ ]:
train_state = checkpoints.restore_checkpoint(jax_model_states, CHECKPOINT_DIR)
print(train_state.step)
tfm._train_state.mdl_vars['params'] = train_state.mdl_vars['params']['core_layer']
tfm.jit_decode()
In [ ]:
mae_losses = []
for batch in tqdm(test_batches.as_numpy_iterator()):
past = batch[0]
actuals = batch[3]
_, forecasts = tfm.forecast(list(past), [0] * past.shape[0])
forecasts = forecasts[:, 0 : actuals.shape[1], 5]
mae_losses.append(np.abs(forecasts - actuals).mean())
print(f"MAE: {np.mean(mae_losses)}")