Skip to main content
App version: 3.4.11

Log parameters and model configuration

You can define a namespace for storing parameters, hyperparameters, configs, or other single values.

In the below examples, the parameters are stored in a namespace called parameters. Inside that namespace, an attribute is created for each parameter.

from neptune_scale import Run


if __name__ == "__main__":
run = Run(experiment_name=...)
run.log_configs(
{
"parameters/learning_rate": 0.001,
"parameters/batch_size": 64,
},
)

You can find your logged configs in the Attributes section of the run.

Logging nested dictionaries

To log nested dictionaries to a Neptune run, use the following helper function to flatten the values:

def flatten_nested(d, parent_key="", sep="/"):
items = {}

if isinstance(d, dict):
for k, v in d.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, (dict, list, tuple, set)):
items.update(flatten_nested(v, new_key, sep=sep))
else:
items[new_key] = v
elif isinstance(d, (list, tuple, set)):
for i, v in enumerate(d):
new_key = f"{parent_key}{sep}{i}" if parent_key else str(i)
if isinstance(v, (dict, list, tuple, set)):
items.update(flatten_nested(v, new_key, sep=sep))
else:
items[new_key] = v
else:
return d

return items

Then pass the flattened dictionary to the log_configs() function:

nested_data = {
"config": {
"learning_rate": 0.001,
},
"metrics": {
"token_count": 76420,
"agg": {
"loss": 0.13,
"acc": 0.97,
}
},
}

if __name__ == "__main__":
run = Run(experiment_name=...)


flattened_data = flatten_nested(nested_data)
run.log_configs(data=flattened_data)

You'll get a similar nested structure in the resulting Neptune run:

run/
|-- config/
|-- learning_rate
|-- metrics/
|-- token_count
|-- agg/
|-- loss
|-- acc

Converting unsupported values

If your dictionary contains data types that Neptune doesn't support, you must convert the values to strings before logging them.

See an example function
def flatten_and_stringify_unsupported(d, parent_key="", sep="/"):

SUPPORTED_DATATYPES = [int, float, str, datetime, bool, list, set]

items = {}
if not isinstance(d, (dict, list, tuple, set)):
return d if type(d) in SUPPORTED_DATATYPES else str(d)
if isinstance(d, dict):
for k, v in d.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, (dict, list, tuple, set)):
items |= stringify_unsupported(v, new_key, sep=sep)
else:
items[new_key] = v if type(v) in SUPPORTED_DATATYPES else str(v)
elif isinstance(d, (list, tuple, set)):
for i, v in enumerate(d):
new_key = f"{parent_key}{sep}{i}" if parent_key else str(i)
if isinstance(v, (dict, list, tuple, set)):
items.update(stringify_unsupported(v, new_key, sep=sep))
else:
items[new_key] = v if type(v) in SUPPORTED_DATATYPES else str(v)
return items

Viewing configs in the app

You can compare configs, scores, and other metadata in the experiments table, side-by-side tab, and custom dashboards.