Saving and Loading Models¶
This tutorial covers how to save trained models to disk and load them for later use, using both athena’s native format and ONNX for interoperability.
Why Save Models?¶
Preserve training results: Avoid retraining
Share models: Distribute trained models to others
Deploy models: Use in production applications
Resume training: Continue from checkpoints
Interoperability: Export to ONNX for use with other frameworks
Athena Native Format¶
Saving a Model¶
Save a network using athena’s native text format:
type(network_type) :: net
! After building and training the network...
! Save to file (simple one-line call)
call net%print(file="trained_model.txt")
The print method saves:
Network architecture (all layer types and configurations)
Trained weights and biases
Optimiser settings
Training metadata (epoch, batch size, loss, accuracy)
Loading a Model¶
Load a previously saved network:
type(network_type) :: net
! Load from file
call net%read(file="trained_model.txt")
! Network is now ready to use
call net%forward(test_data)
call net%compile()
The loaded network includes the complete architecture and all trained parameters.
Currently, it is still necessary to call compile() after loading to ensure checks on network architecture;
for example, to verify layer compatibility, ensure input layers are present and layer connections are valid.
Complete Example¶
Save After Training¶
program save_trained_model
use athena
implicit none
type(network_type) :: net
type(adam_optimiser_type) :: optimiser
type(cce_loss_type) :: loss
real(real32), allocatable :: train_data(:,:), train_labels(:,:)
! Load or generate train_data and train_labels here
! Build network
call net%add(full_layer_type(num_inputs=784, num_outputs=128, activation="relu"))
call net%add(full_layer_type(num_outputs=10, activation="softmax"))
! Compile
optimiser = adam_optimiser_type(learning_rate=0.001_real32)
loss = cce_loss_type()
call net%compile(optimiser=optimiser, metrics=["loss"], loss_method=loss, accuracy_method="mse")
! Train network (assuming train_data and train_labels exist)
call net%train(train_data, train_labels, num_epochs=50, &
batch_size=32)
! Save trained model
call net%print(file="model.txt")
write(*,*) "Model saved successfully!"
end program save_trained_model
Load and Resume Training¶
program resume_training
use athena
implicit none
type(network_type) :: net
real(real32), allocatable :: train_data(:,:), train_labels(:,:)
! Load or generate train_data and train_labels here
! Load the saved model
call net%read(file="model.txt")
call net%compile()
write(*,*) "Model loaded successfully!"
write(*,*) "Previous epoch:", net%epoch
write(*,*) "Previous loss:", net%loss_val
write(*,*) "Previous accuracy:", net%accuracy_val
! Continue training from checkpoint
call net%train(train_data, train_labels, num_epochs=50, &
batch_size=net%batch_size)
! Save updated model
call net%print(file="model_continued.txt")
end program resume_training
Load for Inference¶
program use_saved_model
use athena
implicit none
type(network_type) :: net
real(real32), allocatable :: test_data(:,:,:,:)
real(real32), allocatable :: prediction(:,:)
! Load or generate test_data here
! Load the saved model
call net%read(file="model.txt")
call net%compile()
write(*,*) "Model loaded successfully!"
write(*,*) "Number of layers:", net%num_layers
! Use for predictions (assuming test_data is loaded)
prediction = net%predict(test_data)
end program use_saved_model
Native Format Details¶
File Structure¶
Athena saves models in a human-readable text format with the following structure:
NETWORK_SETTINGS
ATHENA_VERSION = 1.0.0
NAME = my_network
EPOCH = 50
BATCH_SIZE = 32
ACCURACY = 0.987
LOSS = 0.045
LOSS_METHOD = categorical_crossentropy
OPTIMISER: adam
LEARNING_RATE = 0.001
END OPTIMISER
END NETWORK_SETTINGS
FULL || []
NUM_INPUTS = 784
NUM_OUTPUTS = 128
USE_BIAS = T
ACTIVATION: relu
END ACTIVATION
WEIGHTS
(weight values...)
END WEIGHTS
END FULL
... (additional layers)
This format is:
Human-readable: Easy to inspect and debug
Version-tracked: Includes athena version for compatibility
Complete: All architecture and parameters preserved
Editable: Can be manually modified if needed (advanced use)
Model Checkpointing¶
athena does not currently have built-in checkpointing during training, but you can implement this manually by saving the model at desired intervals.
It does, however, print out the current epoch, loss, and accuracy after batch_print_step batches during training, which can help monitor progress.
This argument can be set when calling the train() method.
ONNX Interoperability¶
Athena supports exporting to and importing from ONNX (Open Neural Network Exchange) format for interoperability with other frameworks like PyTorch, TensorFlow, and more. Currently, this uses the human-readable .json-like format, so does not provide the binary efficiency benefits of standard ONNX files.
An example of writing and reading ONNX models can be found here. The example can be run using fpm with the command:
fpm run --example onnx
Note
Whilst the framework for ONNX support in athena is implemented, some layers and features may not yet be fully supported. Please use the issue tracker to report any problems or request additional ONNX features.
Export to ONNX¶
Export a trained athena network to ONNX format:
use athena
implicit none
type(network_type) :: net
! Build and train network...
call net%add(conv2d_layer_type( &
input_shape=[28, 28, 1], &
num_filters=6, kernel_size=3, activation="relu"))
call net%add(maxpool2d_layer_type(pool_size=2, stride=2))
call net%add(full_layer_type(num_outputs=10, activation="softmax"))
call net%compile( &
optimiser=adam_optimiser_type(learning_rate=0.01_real32), &
loss_method="categorical_crossentropy", batch_size=32)
! Export to ONNX
call write_onnx("model.json", net)
The ONNX file can then be:
Loaded in Python with
onnxoronnxruntimeConverted to other formats (PyTorch, TensorFlow, etc.)
Deployed in production environments
Optimised with ONNX Runtime
Import from ONNX¶
Load an ONNX model into athena:
use athena
implicit none
type(network_type) :: net
! Read ONNX file
net = read_onnx("model.json")
call net%compile( &
optimiser=adam_optimiser_type(learning_rate=0.01_real32), &
metrics=["loss"], &
loss_method="cce", accuracy_method="mse" &
)
! Network is ready to use
write(*,*) "Loaded network with", net%num_layers, "layers"
! Use for inference
call net%forward(test_data)
Complete ONNX Example¶
program onnx_example
use athena
implicit none
type(network_type) :: network_write, network_read
character(256) :: onnx_file
! Create a simple network
write(*,*) "Creating a simple test network..."
call network_write%add(conv2d_layer_type( &
input_shape=[28,28,1], &
num_filters=6, &
kernel_size=3, &
activation="relu"))
call network_write%add(maxpool2d_layer_type( &
pool_size=2, &
stride=2))
call network_write%add(full_layer_type( &
num_outputs=12, &
activation="relu"))
call network_write%add(full_layer_type( &
num_outputs=10, &
activation="softmax"))
call network_write%compile( &
optimiser=base_optimiser_type(learning_rate=0.01), &
loss_method="categorical_crossentropy", &
batch_size=1)
! Write network to ONNX
onnx_file = "test_network.json"
write(*,*) "Writing network to ONNX file: ", trim(onnx_file)
call write_onnx(onnx_file, network_write)
write(*,*) "ONNX file written successfully"
! Read network from ONNX
write(*,*) ""
write(*,*) "Reading network from ONNX file..."
network_read = read_onnx(onnx_file)
write(*,*) ""
write(*,*) "Network read completed"
write(*,*) "Number of layers in original network: ", network_write%num_layers
write(*,*) "Number of layers in read network: ", network_read%num_layers
end program onnx_example
ONNX Compatibility¶
Supported operations:
Fully connected (Dense/Gemm/MatMul)
Convolutional (Conv1D, Conv2D, Conv3D)
Pooling (MaxPool, AveragePool)
Activation functions (ReLU, Sigmoid, Tanh, Softmax, etc.)
Batch normalisation
Dropout
Flatten, Reshape
Message passing layers * Duvenaud-style graph convolution * Kipf-style graph convolution
Neural operators
Limitations:
Some athena-specific features may not translate to ONNX
Graph-based layers (message passing) have limited ONNX support
Neural operators can be imported and exported by athena, but currently not supported by other frameworks
Safety and Reliability¶
Save before long training runs: Protect against crashes
Keep multiple checkpoints: Don’t overwrite the only copy
Test loading: Verify models load correctly after saving
Version control: Track model files using tools such as Weights & Biases
Common Issues¶
File Not Found¶
Check file exists before loading:
logical :: file_exists
inquire(file="trained_model.txt", exist=file_exists)
if (.not. file_exists) then
write(*,*) "Error: Model file not found!"
stop
end if
call net%read(file="trained_model.txt")
Version Compatibility¶
The native format includes athena version information:
! Saved files include:
! ATHENA_VERSION = X.Y.Z
Models saved with newer versions may not load in older athena
Check release notes for breaking changes
Test model loading after athena updates
It is always intended that major version updates (e.g., 1.x to 2.x) may introduce breaking changes, so models saved with a newer major version may not be compatible with older versions of athena. Meanwhile, minor version updates (e.g., 1.0 to 1.1) should maintain compatibility where possible.
ONNX Version Issues¶
Athena exports to ONNX IR version 8
Ensure target framework supports this version
Some frameworks may need ONNX model conversion
Next Steps¶
Learn about custom components