Skip to content

Parallelization in RuNNer 2

RuNNer features a hybrid MPI/OpenMP parallelization to make ideal use of the available computational resources. The way the resources are split among MPI tasks and OpenMP threads depends on the specific application. This guide gives an overview about the implementation and practical tips for getting the best performance out of RuNNer.

How to run parallelized calculations with MPI and OpenMP

OpenMP

OpenMP is based on the shared-memory model where threads that are working in parallel can access the same memory space. Here, repeating sections of the code that are independent of each other can be executed by multiple threads to accelerate the runtime. Whereever applicable, RuNNer 2 tries to make use of OpenMP parallelization (e.g. feature calculation, forward/backward passes, QEq). The parallelization is obtained by setting the OMP_NUM_THREADS environment variable to the number of cores that should be available to RuNNer 2. Since in OpenMP all threads need access to the same memory space, a parallelization across nodes by pure OpenMP is not possible.

Library dependencies

Various sections of the RuNNer 2 code rely on BLAS for linear algebraic operations (e.g. forward and backward passes, Kalman filter updates) and LAPACK for solving the linear system of equations in the direct charge equilibration (qeq_method direct). Depending on the respective BLAS and LAPACK implementation, the OpenMP parallelization is already provided (MKL, BLIS, AOCL) or must be built with the respective library (OpenBLAS + LAPACK).

Similarly, the Fast-Fourier-Transformation (FFT) which is used in the electrostatics and iterative charge equilibration is, depending on the respective FFT implementation, already OpenMP parallelized (MKL, AOCL) or must be built with OpenMP support (FFTW3).

Warning

Our tests have shown that the OpenMP parallelization in MKL's FFT implementation in combination with RuNNer 2 built with GNU compilers may not scale as expected. Therefor, be advised to use pure GNU (gfortran + FFTW3) or Intel (ifx + MKL) builds whereever possible.

MPI

MPI: MPI follows the distributed-memory model where each MPI task owns its assigned batch of data. Here, each MPI task executes large parts of the code independently of the other tasks, and most communication only happens with the root task at selected points. In RuNNer 2, the structures from input.data are evenly distributed among the MPI tasks (round-robin). Each task then performs the feature calculation and neural network predictions for its assigned block.

In order to run MPI-parallelized RuNNer 2 calculations, the RuNNer executable must be built with MPI support, see Installation. The calculation can be then launched via

mpirun -np X /path/to/your/RuNNer_mpi.x

with X specifying the number of MPI tasks.

Note

Any memory specification in RuNNer's input files is per MPI task, i.e. the total used memory is max_ram_size times X.

Tip

For hybrid MPI/OpenMP parallelization, please ensure that the number of MPI tasks (on the same node) times the number of OpenMP threads assigned to each task does not exceed the total number of cores on a node. Otherwise, oversubscription of the cores on this node might occur, hindering the performance of RuNNer 2.

Precompute mode

OpenMP

The calculation of the atomic features and feature derivatives are directly parallelized by OpenMP. The size of each parallel loop can be increased with the batchsize_structures keyword, increasing efficiency.

MPI

The structures in the dataset are distributed across MPI task, each task handling the calculation of features and feature derivatives separately. The results are communicated back to the root task for writing to the output files. Thus, the precompute mode scales ideally with the number of MPI tasks until the writing of the feature and feature derivatives to file, which is serial, becomes the bottleneck.

Predict mode

OpenMP

Most notably, the calculation of atomic features and feature derivatives, the forward and backward passes of the atomic neural networks, and the electrostatics (for 3G and 4G) and charge equilibration (for 4G) are parallelized via OpenMP. This covers most of the computationally intensive parts of the prediction, including force and stress evaluation. The parallel efficiency is controlled primarily by the batchsize_structures keyword with additional but smaller gains from the batchsize_elements keyword.

MPI

The structures in the data set are distributed across MPI tasks, and predictions are performed independently for their assigned structures. The predict mode scales perfectly with the number of MPI tasks as long as the number of tasks is smaller than the total number of structures in the data set, ensuring that each task owns at least one structure.

Train mode

OpenMP

Similar to predict mode, most of the prediction of the target properties is parallelized via OpenMP. In addition to that, the calculation of the gradient of the loss with respect to the neural network parameters and, if selected by optimizer (..) kalman[_std], the Kalman Filter updates are parallelized by OpenMP as well.

The parallel efficiency is controlled primarily by the batchsize_structures keyword with additional but smaller gains from the batchsize_elements keyword.

During training with the Kalman filter optimizer, the parameter updates often become the primary bottleneck. Since Kalman matrices are typically small, the OpenMP parallelization often only provides a decent speedup up to a small number of threads. In these cases, it is advisable to switch to MPI training instead.

Note

Be aware that batchsize_structures also affects the training process. For further details, see here.

MPI

Structures are distributed across the MPI tasks. Each task independently predicts the target property and computes the loss and its gradients. For the parameter update, all losses and gradients are sent to the root task, where they are averaged and used to update the model. This yields an effective batch size equal to the number of MPI tasks. The updated neural network parameters are then broadcast to all tasks.

This approach is termed "multistream training".

Hint

In the (Multistream)-Kalman Filters, the loss and loss gradients coming from each task appear as additional dimension in the Kalman matrices (streams), effectively increasing the dimensions of matrix multiplications.

Effectiveness of MPI training

The training can be accelerated with MPI, however this effectively reduces the number of updates. Thus, the training results explicitly depend on the number of MPI tasks. However, we have often found that MPI training yields low cost metrics in a comparable number of epochs as serial training due to very efficient batching.

Interfaces

OpenMP

Same as in predict mode. When using RuNNer 2 as a library inside an MD executable, ensure that both the MD code and the RuNNer 2 library are linked against the same OpenMP runtime to avoid oversubscription or runtime errors.

MPI

Supported in combination with LAMMPS. LAMMPS decomposes the system into spatial subdomains processed independently by MPI tasks with the RuNNer 2 library evaluating the local energy/force/stress contributions on each task, which LAMMPS then communicates across the tasks. Parallel efficiency generally improves with larger systems (more atoms per subdomain). Exception: for 4G-HDNNP models the required global charge equilibration is performed on the root task, introducing a bottleneck that severely limits the parallelization by MPI.

Hint

For 4G-HDNNP driven MD simulations, prefer OpenMP instead.