2026-07-15
The material for this workshop, including a link to the slides to follow on your own device, can be found at: github.com/Cambridge-ICCS/FTorch-workshop
Except where otherwise noted, these presentation materials are licensed under the Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) License.
Vectors and icons by SVG Repo under CC0(1.0) or FontAwesome under SIL OFL 1.1
In this tutorial, we will be using GitHub Codespaces to run the exercises. If you are not familiar with Codespaces, please refer to the Codespaces documentation for more information.
FTorch-workshop, not FTorch.We typically think of Deep Learning as an end-to-end process;
a black box with an input and an output1.

Who’s that Pokémon?
\[\begin{bmatrix}\vdots\\a_{23}\\a_{24}\\a_{25}\\a_{26}\\a_{27}\\\vdots\\\end{bmatrix}=\begin{bmatrix}\vdots\\0\\0\\1\\0\\0\\\vdots\\\end{bmatrix}\] It’s Pikachu!
Neural Net by 3Blue1Brown under fair dealing.
Pikachu © The Pokemon Company, used under fair dealing.

Neural Net by 3Blue1Brown under fair dealing.
Pikachu © The Pokemon Company, used under fair dealing.
Many large scientific models are written in Fortran (or C, or C++).
Much machine learning is conducted in Python.




![]()


![]()
Mathematical Bridge by cmglee used under CC BY-SA 3.0
PyTorch, the PyTorch logo and any related marks are trademarks of The Linux Foundation.”
We consider 2 types:
Computational
Developer
Both affect ‘time-to-science’.

iso_c_binding module (intrinsic since 2003).Torch and PyTorch logos under Creative Commons
![]()

![]()

![]()
Python
env
Python
runtime


xkcd #1987 by Randall Munroe, used under CC BY-NC 2.5
![]()
For more details on the development see slides and recording from a recent talk here: jackatkinson.net/slides/Oxford-FTorch/
Or, for the lastest on what’s new in FTorch, see jackatkinson.net/slides/CESM-Jun-26
The key learning objective from this workshop could be simply summarised as:
Provide the ability to couple PyTorch models to Fortran using FTorch.
However, more specifically we aim to:
FTorch is available from GitHub:
github.com/Cambridge-ICCS/FTorch
With supporting documentation at:
cambridge-iccs.github.io/FTorch/
For the purposes of this workshop using GitHub codespaces FTorch is built when sourcing the build_FTorch.sh script.
This downloads the FTorch source from GitHub, installs libtorch through PyTorch, and then uses CMake to build FTorch and link it to libtorch.
If you want to build locally you can inspect this script for more details and consult the comprehensive online documentation.
The source code for FTorch is contained in the src/ directory. This contains:
ctorch.cpp - Bindings to the libtorch C++ API.ctorch.h - C header file to bind to from Fortran.ftorch.f90 - the umbrella module that uses submodules containing the Fortran routines we will be calling (ftorch_devices.F90, ftorch_types.f90, ftorch_tensor.f90, ftorch_model.f90, ftorch_optim.f90).
These are compiled, linked together, and installed using CMake.
CMakeLists.txt file.FTorch includes a pip-installable Python library ftorch_utils that installs the handy pt2ts command-line utility for converting Python models to TorchScript.
It also installs PyTorch and other dependencies as required by the FTorch examples suite.
If installing in codespaces using build_FTorch.sh these will be installed into a Python virtual environment for you.
Question: What are people’s experience levels with and use cases of Fortran and PyTorch?
Navigate to exercises/exercise_00/ where you will see both Python and Fortran files.
hello_pytorch.py defines a net SimpleNet that takes an input vector of length 5 and multiplies it by 2.
Note:
nn.Module classforward() methodRunning:
should produce the output:
First we will check that we have a Fortran compiler and CMake installed:
Running:
Should produce output similar to:
GNU Fortran (Homebrew GCC 14.1.0_1) 14.1.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
cmake version 3.31.0
CMake suite maintained and supported by Kitware (kitware.com/cmake).The file hello_fortran.f90 contains a program to take an input array and call a subroutine to multiply it by two before printing the result.
The subroutine is contained in a separate module math_mod.f90, however.
Now we will compile the code using CMake.
First create a build directory and generate build scripts using CMake:
Now that we have FTorch installed on the system we can move to writing code that uses it, needing only to link to our installation at compile and runtime.
We will start of with a basic example showing how to couple code in Exercise 1:
Examine exercises/exercise_01/simplenet.py.
This contains a contrived PyTorch model with a single nn.Linear layer that will multiply the input by two.
With our virtual environment active we can test this by running the code with1:
Input: tensor([0., 1., 2., 3., 4.])
Output: tensor([0., 2., 4., 6., 8.])
To use the net from Fortran we need to save our PyTorch net as TorchScript in a .pt file.
FTorch comes with a handy utility pt2ts to help with this, which is installed alongside the Python components of the library.
We run simplenet.py to produce a PyTorch model file (.pt file with the model architecture and weights), then use the pt2ts command to convert it to TorchScript ready for use from Fortran.
We already ran
Run
to check that the pytorch_simplenet_input_tensor_cpu.pt file was created.
Then convert to TorchScript using the pt2ts command:
Now run
to check that the torchscript_simplenet_input_tensor_cpu.pt file was created.
We are now in a state to use our saved TorchScript model from within Fortran.
exercises/exercise_01/simplenet_fortran.f90 contains a skeleton code with a Fortran arrays to hold input data for the net, and the results returned.
We will modify it to create the neccessary data structures and load and call the net.
ftorch module.torch_tensors and a torch_model to hold the data and net.torch_tensors.torch_model_forward to run the net.Once we have modified the Fortran we need to compile the code and link it to FTorch.
This can be done from the exercise_01/ subdirectory using CMake as follows:
To run the code we can use the generated executable:
Model parameters:
_fwd_seq.0.weight:
2 0 0 0 0
0 2 0 0 0
0 0 2 0 0
0 0 0 2 0
0 0 0 0 2
[ CPUFloatType{5,5} ]
Model output:
0.00000000 2.00000000 4.00000000 6.00000000 8.00000000
In exercise 1 we used a contrived model, SimpleNet, with a 1-D input.
In this exercise we take a step up using a real-world example: classifying images with a pre-trained ResNet-18 model from TorchVision.
We will reinforce what we learnt in exercise 1 whilst using multidimensional data and briefly exploting batched data as an extension. As part of this we will also discuss data layout differences between Python (row-major) and Fortran (column-major).
Navigate to exercises/exercise_02/.
You will find:
generate_input_batch.py – preprocesses image(s) to a binary data file.resnet_infer_python.py – Run resnet from Python.resnet_infer_fortran.f90 – template with ! TODO comments.resnet_infer_fortran_sol.f90 – complete solution.data/ – example images and ImageNet labels.Generate input:
takes images in data/, and pre-processes them ready for input to the ResNet model.
Convert to TorchScript:
downloads a model definition and weights from TorchVision and saves it to TorchScript.
Verify inference works in Python:
Image 0: Samoyed, probability 0.8846Fortran: Build using CMake, completing the TODOs in resnet_infer_fortran.f90, then run:
The Fortran arrays are already set up for you to read data from file:
You need to:
torch_model and torch_tensor variables.torch_tensor_from_array.torch_model_load.
model_file.torch_model_forward.Now extend from single-image to multi-image inference:
Generate a larger batch by editing generate_input_batch.py to include dog2.jpg (and any other images you download). Re-run the script.
Run with batch_size 2:
Verify the results in Python:
Python (C) and Fortran store arrays in opposite memory order:
This is why we transpose the data in Python before saving when generating the batch input:
transpose() reverses axes from [B, C, H, W] to [W, H, C, B].
This means that when read into memory by Fortran they will appear structured as we expect. FTorch then uses Torch’s strided memory access to account for differences in layout meaning the arrays can appear the same to the user in both Fortran and Python.
See the online docs for more detail.
What we have considered so far is a simple contrived example designed to teach the basics.
However, in reality the codes we will be using are more complex, and full of terrors.
In exercise 3 we will look at an example of how to ideally structure a slightly more complex code setup. For those familiar with climate models this may be nothing new. We make use of the traditional separation into subroutines for:
Navigate to the exercises/exercise_03/ directory.
Here you will see two code directories, good/ and bad/.
Both perform the same operation:
The exercise is the same for both folders:
pt2ts command to save the net (as in exercise 1).simplenet_fortran.f90.fortran_ml_mod.f90.
bad is in a single routine.good is split into init, iter, and finalise.For a complete version of the example, see the Looping example.
PyTorch has a powerful automatic differentiation engine called autograd that can be used to compute derivatives of expressions involving tensors.
We recently exposed this functionality in FTorch, allowing you to do this in Fortran, too. This is a key step facilitating online training in FTorch.
In this exercise, we walk through differentiating the mathematical expression \[Q = 3 (a^3 - b^2/3)\] using both PyTorch and FTorch.
Supply as an array of tensors, innit.
pt2ts, save the model on GPU.
torch_tensors set the device to torch_kCUDA instead of torch_kCPU.1device_index argument.MPI_GATHER() to reduce.torch_tensor_to to transfer tensors between devices (and data types).For more information please speak to us afterwards, or drop us a message.
Thanks to the rest of the FTorch team and contributors.
The ICCS received support from 
FTorch has been supported by 

