Jonathan Mackenzie
04/29/2025, 3:04 AMOlivier
04/30/2025, 2:26 PMRodrigo Sodré
04/30/2025, 5:22 PMJonathan Mackenzie
05/01/2025, 12:02 AMMarco
05/05/2025, 12:34 PMJonathan Mackenzie
05/06/2025, 4:29 AMMarco
05/06/2025, 10:28 AMJonathan Mackenzie
05/06/2025, 10:29 AMOlivier
05/06/2025, 10:36 AMJonathan Mackenzie
05/06/2025, 10:45 AMtest_df.iloc[0]
Out[12]:
timestamp 2025-01-01 18:10:00
ac_power_site 0.0
irradiance 0.0
daily_energy_site 375.47
daily_energy_inverter_1 124.19
ac_power_inverter_1 0.0
daily_energy_inverter_2 117.41
ac_power_inverter_2 0.0
daily_energy_inverter_3 133.88
ac_power_inverter_3 0.0
air_temperature 17.8
air_pressure 1013.2
humidity 84.0
sunshine_duration 0.0
solar_radiation 0.0
unique_id S034
We wanted to also make a model for the individual inverters that make up the whole solar plant
My code looks like this:
def train(site, inverter, target_prefix="daily_energy"):
"""
Train a model using neuralforecast NHITS model for a given site or inverter
"""
if not inverter:
target = f"{target_prefix}_site"
else:
target = f"{target_prefix}_{inverter}"
data = load_data(site)
df = data.reset_index(drop=False)
print(f"Training site={site} inverter={inverter} target={target}")
# drop null values
# get weather prediction value
df = df.dropna(subset=['timestamp', 'irradiance', target])
split_idx = int(0.8 * len(df))
train_df = df.iloc[:split_idx]
test_df = df.iloc[split_idx:]
horizon = 96 # n predictions at 10 minutes ahead
tb_logger = TensorBoardLogger(save_dir="tb_logs", name="solar_tb_logs")
extra_fields = [
'irradiance',
'air_temperature',
'air_pressure',
'humidity',
'sunshine_duration',
'solar_radiation',
]
# Use your own config or AutoNHITS.default_config
nhits_config = {
"learning_rate": tune.choice([1.9e-7]),
"max_steps": tune.choice([1024]), # Number of SGD steps
"input_size": tune.choice([5 * horizon, 3 * horizon, 8 * horizon]), # input_size = multiplier * horizon
"batch_size": tune.choice([32, 16, 8]), # Number of series in windows
"windows_batch_size": tune.choice([128, 256, 512, 1024]), # Number of windows in batch
"n_pool_kernel_size": tune.choice(
[[2, 2, 1], 3 * [1], 3 * [2], 3 * [4], [8, 4, 1], [16, 8, 1]]
), # MaxPool's Kernel size
"n_freq_downsample": tune.choice([[168, 24, 1], [24, 12, 1], [4, 2, 1], [1, 1, 1]]),
"hist_exog_list": tune.choice([extra_fields]),
# Interpolation expressivity ratios
"activation": tune.choice(['ReLU']), # Type of non-linear activation
"n_blocks": tune.choice([[1, 1, 1]]), # Blocks per each 3 stacks
"mlp_units": tune.choice([3 * [[512, 512]], 4 * [[512, 512]], 5 * [256, 256]]),
"early_stop_patience_steps": tune.choice([4]),
# 2 512-Layers per block for each stack
"interpolation_mode": tune.choice(['linear']), # Type of multi-step interpolation
"val_check_steps": tune.choice([20]), # Compute validation every 100 epochs
"random_seed": tune.randint(1, 20),
"logger": tune.choice([tb_logger]),
"callbacks": tune.choice([[LearningRateFinder()]])
}
nf = NeuralForecast(
models=[
AutoNHITS(
h=horizon,
config=nhits_config,
num_samples=16,
),
],
freq='10min'
)
# print("Best config", nf.models[0].results.get_best_result().config)
nf.fit(
df=df[['unique_id', 'timestamp', target] + extra_fields],
time_col="timestamp",
target_col=target,
val_size=int(0.15 * len(train_df)),
)
if inverter:
model_name = f"{site}_inverter_{inverter}_h_{horizon}"
else:
model_name = f"{site}_site_h_{horizon}"
model_output = root_path / 'models' / model_name
nf.save(str(model_output), overwrite=True, save_dataset=False)
print("Writing to", model_output)
return nf, train_df, test_df, target, f"{site} {inverter}"
Olivier
05/06/2025, 10:56 AMtrain_df
, not the full df
, no? Second, do you have more than one unique_id? Otherwise there's an error in how you create the train and test sets - do that by doing e.g. df.groupby(["unique_id"], sort=False).tail(20)
if you want to keep the last 20 timesteps. Make sure the dataframe is sorted too before making the split: df.sort_values(by=["unique_id", "ds"])
. I'll come back later but these are a few easy things from looking at your code.Jonathan Mackenzie
05/06/2025, 10:57 AMOlivier
05/06/2025, 11:00 AMscaler_type
set which is usually in any algorithm the most important hyperparameter. Learning rate doesn't make sense, way too low. Just start with the default config of AutoNHITS.Jonathan Mackenzie
05/06/2025, 11:01 AMJonathan Mackenzie
05/06/2025, 11:01 AMOlivier
05/06/2025, 11:02 AMOlivier
05/06/2025, 11:04 AMnhits_config = {
"scaler_type"= tune.choice(["minmax1", "robust", "identity"]),
"max_steps"=tune.choice([500, 1000, 2000, 5000]),
}
Jonathan Mackenzie
05/06/2025, 11:04 AMOlivier
05/06/2025, 11:07 AM