Machine Learning#
Machine learning refers to a set of techniques and algorithms that enable computers to automatically learn from data and improve their performance on a specific task over time. Types of machine learning methods include, but are not limited to, supervised learning (algorithms trained on labeled datasets), unsupervised learning (algorithms trained on unlabeled datasets), and reinforcement learning (learning by trial and error). The Computational Science Center at NLR conducts research in these types of machine learning, and also supports the use of machine learning software on Kestrel.
Getting Started#
This page covers running the two most popular machine learning libraries on Kestrel: PyTorch and TensorFlow. The examples use Anaconda environments, so if you are not familiar with their use please refer to the NLR HPC page on using Conda environments and also the Conda guide to managing environments.
The page is organized by framework. Each framework section covers CPU installation, GPU installation, the pre-built GPU module, and a worked example. Shared job scripts and installing on Gila are covered at the end.
On most computing systems, these frameworks are often installed via Python virtual environments or package managers including conda or pixi. Although Kestrel users are able to manage these frameworks in the same manner, it is strongly recommended that any Kestrel environments destined for running on multiple GPU nodes are built from NLR-managed modules for either PyTorch or TensorFlow so the framework can leverage the full speed offered by the Slingshot interconnect. In comparison to the equivalent software module, Kestrel users attempting to use pip-installed versions of PyTorch or TensorFlow will likely see signficant performance degradation when running across multiple nodes. pip-installed versions of these frameworks are expected to have the same performance as those from the software modules only when running on a single node.
Note
This page is only scratching the surface of ML libraries and resources that can be used on Kestrel. Tools such as LightGBM, XGBoost, and scikit-learn work well with conda environments, and other tools such as Flux for the Julia Language can be used on Kestrel as well.
Note
We recommend installing software for GPU jobs using the GPU nodes. There are two GPU login nodes available on Kestrel.
To install either PyTorch or TensorFlow for use with GPUs on Kestrel via Anaconda virtual environments, the first step is to load the anaconda module on the GPU node using module load conda. Once this module has been loaded, create a new environment in which to install PyTorch or TensorFlow, e.g.,
Creating and activating a new conda environment
conda create --prefix /projects/<your-project-name>/<your-user-name>/<conda-env-dir>/pt python=3.9
conda activate /projects/<your-project-name>/<your-user-name>/<conda-env-dir>/<pt or tf>
Note
If you are not familiar with using Anaconda environments please refer to the NLR HPC page on using Conda environments and also the Conda guide to managing environments.
PyTorch#
Installing PyTorch (CPU)#
To begin, we will outline basic steps for building a simple CPU-based conda environment for PyTorch. First, load the anaconda module and create a new conda environment:
module load anaconda3
conda create -p /projects/YOUR_PROJECT/YOUR_USER_NAME_HERE/FOLDER_FOR_CONDA_ENVIRONMENTS/pt python=3.9
Activate the pt conda environment and install PyTorch into the active conda environment:
conda activate /projects/YOUR_PROJECT/YOUR_USER_NAME_HERE/FOLDER_FOR_CONDA_ENVIRONMENTS/pt
conda install pytorch torchvision torchaudio cpuonly -c pytorch
Installing PyTorch (GPU)#
Kestrel users are strongly recommended to use the pre-built pytorch modules directly or build from them based on the instructions below, depending on which OS your target node is using:
Pre-built PyTorch GPU module#
RHEL8: Pre-built pytorch/2.10.0 module
A pre-built pytorch module is available on Kestrel as an experimental alternative to the conda-unpack based approach below. It provides PyTorch 2.10.0 with CUDA 12.4, NCCL 2.23.4, and Python 3.11. It is for GPU nodes only.
Load it with:
module load pytorch
which will print usage instructions:
PyTorch 2.10.0 loaded (CUDA 12.4 | NCCL 2.23.4 | Python 3.11 | H100/sm_90 only)
No extra packages needed? Use directly:
python3 your_script.py
Option 1 — venv (recommended when you need extra pip packages):
python3 -m venv /scratch/$USER/myenv --system-site-packages
source /scratch/$USER/myenv/bin/activate
pip install <your-packages>
Option 2 — conda env (only when you need non-Python deps like compiled libs or tools):
conda create -p ~/myenv <non-python-deps>
conda activate ~/myenv
$PYTORCH_PYTHON \
-m venv ~/myenv/pyenv --system-site-packages
source ~/myenv/pyenv/bin/activate
pip install <your-packages>
NOTE: do NOT 'conda install' Python packages — use the venv pip instead.
RHEL9: Pre-built pytorch/2.12.0 module
Several versions of pre-built pytorch modules are available on Kestrel RHEL9 nodes. The default version provides PyTorch 2.12.0 with CUDA 13.2, NCCL 2.27.7, and Python 3.12. It is for GPU nodes only.
Load it with:
module load pytorch/2.12.0
which will print usage instructions:
PyTorch 2.12.0 loaded (CUDA 13.2 | Python 3.12.13 | H100/sm_90 only)
No extra packages needed? Use directly:
python3 your_script.py
Option 1 — venv (recommended when you need extra pip packages):
python3 -m venv /scratch/$USER/myenv --system-site-packages
source /scratch/$USER/myenv/bin/activate
pip install <your-packages>
Option 2 — conda env (only when you need non-Python deps like compiled libs or tools):
conda create -p ~/myenv <non-python-deps>
conda activate ~/myenv
/nopt/nlr/apps/kestrel-gpu/software/pytorch/shs-libfabric/2.12.0/bin/python3 -m venv ~/myenv/pyenv --system-site-packages
source ~/myenv/pyenv/bin/activate
pip install <your-packages>
NOTE: do NOT 'conda install' Python packages — use the venv pip instead.
Full documentation:
/nopt/nlr/apps/kestrel-gpu/software/pytorch/shs-libfabric/2.12.0/../USER_GUIDE.md
To suppress this message: module -q load pytorch/2.12.0
Generic PyTorch installation#
Users can also install PyTorch in an activated python environment using the standard approach found under the Get Started tab of the PyTorch website, e.g., using pip. PyTorch installed in this manner is not expected to scale well on multiple GPU nodes, but should have good performance within a single GPU node:
Installing PyTorch using pip
pip3 install torch torchvision torchaudio
PyTorch Example#
Below we present a simple convolutional neural network example for getting started using PyTorch with Kestrel GPUs. The original, more detailed version of this example can be found in the pytorch tutorials repo here.
CIFAR10 example
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# Check if there are GPUs. If so, use the first one in the list
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print(device)
# Load data and normalize
transform = transforms.Compose(
[transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
batch_size = 4
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
shuffle=False, num_workers=2)
# Define the CNN
class Net(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = torch.flatten(x, 1) # flatten all dimensions except batch
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
# send the network to the device
# If you want to use data parallelism across multiple GPUs, uncomment if statement below
#if torch.cuda.device_count() > 1:
# net = nn.DataParallel(net)
net.to(device)
# Define loss function and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# Train the network
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
# inputs, labels = data # setup without device
inputs, labels = data[0].to(device), data[1].to(device)
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')
running_loss = 0.0
print('Finished Training')
Note
Currently, this code will run on a single GPU, specifically the GPU denoted cuda:0. To use multiple GPUs via data parallelism, uncomment the two lines above the net.to(device) command. Furthermore, use of multiple GPUs require requesting multiple GPUs for the batch or interactive job.
Note
To better observe the multi-GPU peformance of the above example, you can change the size of the CNN. For example, by increasing the size of the second argument in the definition of self.conv1 and the first argument in self.conv2, you can increase the size of the network and use more resources for training.
TensorFlow#
Installing TensorFlow (CPU)#
Getting started with TensorFlow on CPU is similar to the process for PyTorch. The first step is to construct an empty conda environment to work in:
module load anaconda3
conda create -p /projects/YOUR_PROJECT/YOUR_USER_NAME_HERE/FOLDER_FOR_CONDA_ENVIRONMENTS/tf python=3.9
conda activate /projects/YOUR_PROJECT/YOUR_USER_NAME_HERE/FOLDER_FOR_CONDA_ENVIRONMENTS/tf
pip install --upgrade pip
pip install tensorflow-cpu
Installing TensorFlow (GPU)#
Presented below are instructions for installing TensorFlow following in the pip install instructions found here: TensorFlow. For optimized TensorFlow performance, we recommend using a containerized version of TensorFlow.
You can install TensorFlow using the pip based approach described in TensorFlow, but with a couple modifications. Instead of using the cudatoolkit, we recommend using the default gnu programming environment accessed using the module PrgEnv-gnu/8.5.0. The nccl/2.21.5_cuda124 module loads its corresponding cuda/12.4. Using these modules, we install TensorFlow with the following commands:
Installing TensorFlow using pip
ml PrgEnv-gnu/8.5.0
ml anaconda3 nccl/2.21.5_cuda124
conda create -p ./tf-env python=3.11 pip -y
conda activate ./tf-env
pip install tensorflow[and-cuda]==2.18.0
Pre-built TensorFlow GPU module#
Experimental: Pre-built tensorflow/2.21.0 module (RHEL 9 GPU)
A pre-built tensorflow module is available on Kestrel's RHEL 9 GPU
nodes as an alternative to building your own environment. It provides
TensorFlow 2.21.0 with Python 3.12 and GPU support for H100 (sm_90).
CUDA 12.9 and cuDNN come from the tensorflow[and-cuda] pip
wheels, while the on-node Slingshot-tuned NCCL 2.27.7 (libfabric-CXI) and
system cuDNN 9.17 are layered in for correct multi-node collectives and to
avoid an H100 conv-backprop regression under MirroredStrategy.
The module is reachable from the RHEL 9 GPU login node kl5 (log in
there, or ssh kl5 from a RHEL 9 login). Load it with:
module load tensorflow
which prints usage instructions:
TensorFlow 2.21.0 loaded (CUDA 12.9-bundled | Python 3.12 | H100/sm_90 only)
NCCL: Kestrel Slingshot 2.27.7 (overrides bundled 2.30.7 for fabric perf)
cuDNN: system 9.17 (overrides bundled 9.24 - avoids "No algorithm worked"
regression on H100 conv-backprop under MirroredStrategy)
Use it directly, or build a lightweight personal venv on top when you need extra packages:
# Use directly
python3 your_script.py
# Personal venv on top (recommended for extra pip packages)
python3 -m venv /scratch/$USER/tf_env --system-site-packages
source /scratch/$USER/tf_env/bin/activate
pip install <your-extras>
Note
Do not combine --system-site-packages with a conda environment,
and do not conda install Python packages on top of the module — use
the venv pip instead.
For multi-node MPI (the bundled mpi4py is built against Kestrel's MPICH
4.3.2), launch with srun:
srun --mpi=pmi2 -n <N> python3 your_mpi_script.py
Slurm auto-allocates a Slingshot VNI for pmi2 jobs when nodes >= 2. To
force one explicitly (e.g. single-node MPI), add --network=job_vni (or
--network=single_node_vni) to salloc/srun. TensorFlow's own
MultiWorkerMirroredStrategy uses gRPC + NCCL and is unaffected.
Full details are in the guide at
/nopt/nlr/apps/kestrel-gpu/software/tensorflow/tensorflow-2.21.0-guide.md.
TensorFlow Example#
Find below a simple neural network example using the MNIST data set for getting started using TensorFlow with Kestrel GPUs. This example was based on TensorFlow's quick start documentation found here.
MNIST example
import tensorflow as tf
# Select a standard data set and normalize
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
# Set up and compile a model
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation='softmax')])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Fit model to training data and evaluate on test data
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)
Installing PyTorch on Gila#
The Gila cluster hosts two types of accelerator nodes. Although both types use GPU drivers compatible with cuda/13.1, critically, they differ in their overall chip architecture:
- NVIDIA A100 GPUs with Intel Xeon Icelake CPUs nodes (
x86) - NVIDIA Grace Hopper nodes (
arm)
Note
Python/conda environments built on Gila will only work for either x86 or arm architectures depending on which node was used to create them. In other words, an environment created on an x86-based node hosting A100s would not be expected to work on an arm-based Grace Hopper node (and vice versa). This is generally true for all software managed on Gila. As such, always ensure you are using an environment that was created on the same node architecture you plan to run it on.
Regardless of architecture, installing an accelerated version PyTorch on Gila is straightforward; simply load the cuda and miniforge3 modules and pass the appropriate index-url to use cuda 13+ wheels. This example reflects a minimal arm-based environment that starts with python and the numpy package. Note that in this example, a project's .conda-envs folder is assumed to be organized to include arm and x86 subfolders to distinguish environments created for the two different types of architectures:
Creating an arm-based PyTorch environment for Grace Hopper nodes on Gila
# Connect to the arm login node
ssh gila-arm.hpc.nlr.gov
# Request partial Grace Hopper node for 15 minutes to create arm-based environment
# Replace <allocation handle> accordingly
salloc -A <allocation handle> -p gh -t 00:15:00 --mem-per-cpu=2G -n 1 -c 8 --gres=gpu:1
# Define location for PyTorch environment (don't forget to replace <allocation handle>!)
EXAMPLE_TORCH_ENV=/projects/<allocation handle>/.conda-envs/arm/torch-test-env
# Load modules, create env, and use pip to install torch into it
ml cuda/13.1 miniforge3
mamba create --prefix=$EXAMPLE_TORCH_ENV python numpy -y
conda activate $EXAMPLE_TORCH_ENV
pip install torch --index-url https://download.pytorch.org/whl/cu130
Job Scripts#
The following job scripts work for either PyTorch or TensorFlow — activate the
appropriate environment (or module load pytorch / module load tensorflow)
and point srun at your script.
PyTorch or TensorFlow shared partition CPU example
#!/bin/bash
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --mem=64G
#SBATCH --cpus-per-task=26
#SBATCH --partition=shared
#SBATCH --account=<your account>
#SBATCH --time=00:30:00
module load conda
conda activate /projects/<your_project>/<conda_envs_dir>/<pt_or_tf>
srun python <your_code>.py
Once you have completed your batch file, submit using
sbatch <your_batch_file_name>.sb
Sample job script: Kestrel - Shared (partial) GPU node
#!/bin/bash
#SBATCH --account=<your-account-name>
#SBATCH --nodes=1
#SBATCH --gpus=1
#SBATCH --ntasks-per-node=1
#SBATCH --mem=96G
#SBATCH --cpus-per-task=32
#SBATCH --time=00:30:00
#SBATCH --job-name=<your-job-name>
module load conda
conda activate /projects/<your-project-name>/<your-user-name>/<conda-env-dir>/<pt or tf>
srun python <your-pytorch or tensorflow-code>.py