Setting up CUDA on WSL2 in 2023

August 24, 2023

Setting up CUDA on WSL2 probably costs you a little bit of performance but gives you a lot of flexibility - you're essentially running a VM with (some) Microsoft support. Here's the best source: Enable NVIDIA CUDA in WSL.

Luckily in the past year or so NVIDIA has started supporting this path, so you're (kind of) in good hands. A lot of advice will be mixed between Ubuntu and WSL, though, so I'm writing down my experience with installing CUDA on WSL2 today.

The below is a bit of a bloated install, so you might be able to get away with fewer things (for example TensorRT is pretty optional).

Install drivers

First, you'll need to get an NVIDIA driver (in Windows) for your card. I got the "NVIDIA Game Ready" driver from NVIDIA's website directly. Note that this is not installing an NVIDIA driver for your WSL (i.e. Linux) installation. As far as I can tell, this process uses your Windows driver directly (which makes sense, having two drivers for the same physical device running seems like a recipe for disaster).

I chose:

  • No GEForce Experience
  • HD Audio Driver
  • PhysX

though of course you can make other choices. Once this is finished, you will see a bunch of files in C:\Windows\System32\lxss\lib\:

~ ❯ ls -l /mnt/c/Windows/System32/lxss/lib/
-r-xr-xr-x 1 singhrac singhrac 10188744 Aug 15 00:23 libcudadebugger.so.1
-r-xr-xr-x 1 singhrac singhrac   154088 Aug 15 00:23 libcuda.so
-r-xr-xr-x 1 singhrac singhrac   154088 Aug 15 00:23 libcuda.so.1
-r-xr-xr-x 1 singhrac singhrac   154088 Aug 15 00:23 libcuda.so.1.1
-r-xr-xr-x 3 singhrac singhrac  5401440 Aug 11 11:05 libd3d12core.so
-r-xr-xr-x 3 singhrac singhrac   800296 Aug 11 11:05 libd3d12.so
-r-xr-xr-x 2 singhrac singhrac   827904 Jun  5  2021 libdxcore.so
-r-xr-xr-x 1 singhrac singhrac 10820792 Aug 15 00:23 libnvcuvid.so
-r-xr-xr-x 1 singhrac singhrac 10820792 Aug 15 00:23 libnvcuvid.so.1
-r-xr-xr-x 1 singhrac singhrac 37086552 Aug 15 00:23 libnvdxdlkernels.so
-r-xr-xr-x 1 singhrac singhrac   551528 Aug 15 00:23 libnvidia-encode.so
-r-xr-xr-x 1 singhrac singhrac   551528 Aug 15 00:23 libnvidia-encode.so.1
-r-xr-xr-x 1 singhrac singhrac   233832 Aug 15 00:23 libnvidia-ml.so.1
-r-xr-xr-x 1 singhrac singhrac   362960 Aug 15 00:23 libnvidia-opticalflow.so
-r-xr-xr-x 1 singhrac singhrac   362960 Aug 15 00:23 libnvidia-opticalflow.so.1
-r-xr-xr-x 1 singhrac singhrac    68560 Aug 15 00:23 libnvoptix.so.1
-r-xr-xr-x 1 singhrac singhrac 83265296 Aug 15 00:23 libnvwgf2umx.so
-r-xr-xr-x 1 singhrac singhrac   678064 Aug 15 00:23 nvidia-smi

and the same set of files in /usr/lib/wsl/lib/. NOTE! This is the location that the CUDA Runtime will live. However, you also need the CUDA Toolkit (probably). Note that nvidia-smi will now work if you add /usr/lib/wsl/lib/ to your path:

~ ❯ nvidia-smi
Thu Aug 24 11:17:06 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.103                Driver Version: 537.13       CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA GeForce RTX 2070        On  | 00000000:07:00.0  On |                  N/A |
|  0%   51C    P5              20W / 175W |    573MiB /  8192MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|  No running processes found                                                           |
+---------------------------------------------------------------------------------------+

However the "CUDA Version" at the top is the max supported CUDA Toolkit version that you can use1. At this point in time (20230824) PyTorch doesn't really support CUDA 12.2, so it might be a huge pain in the ass if you use that. I recommend 11.8, the currently max supported version on the install page. I'm sure this will change shortly.

At this point, you probably want to add /usr/lib/wsl/lib/ to your LD_LIBRARY_PATH, which will let programs find the .so files there. Put this in your ~/.bashrc or ~/.zshrc:

export LD_LIBRARY_PATH=/usr/lib/wsl/lib:$LD_LIBRARY_PATH

If you run ldconfig -p | grep libcuda, this will now show those libraries (you might have to exec zsh or restart your shell).

Install CUDA Toolkit

It is really important to listen to NVIDIA's instructions here: the default CUDA Toolkit comes with a driver, which will overwrite the above set (i.e. piggy-backing off Windows driver). So it's important to install the WSL-specific CUDA Toolkit, which doesn't have that driver. This is also where it's really easy to install the latest CUDA Toolkit (i.e. 12.2), which might cause issues for you. I didn't run into too many the first time, but I think it's easier just to install the older toolkit.

Go here: CUDA Toolkit 11.8. You can find other versions in the "Archive of Previous CUDA Releases" link.

You want to choose: Linux > x86_64 > WSL-Ubuntu > 2.0 > (your choice of installer type)

I personally find it easier to deal with deb installation because then things like dpkg will help you manage the installation, but everyone's experience is different. In any case, you want to follow those instructions, making sure you have WSL-Ubuntu selected. If you use the deb (network) install, it might try to install 12.2 because that's the most recent version. I think you can work around this by doing sudo apt-get install cuda-toolkit-11-8, but I used the deb (local) version instead.

I personally ran:

~ ❯ wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
~ ❯ sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
~ ❯ wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
~ ❯ sudo dpkg -i cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
~ ❯ sudo cp /var/cuda-repo-wsl-ubuntu-11-8-local/cuda-*-keyring.gpg /usr/share/keyrings/
~ ❯ sudo apt-get update
~ ❯ sudo apt-get -y install cuda-toolkit-11-8

Note the change in the last line - I wanted to pin the specific version. This installs a lot of stuff for you: nvprof, nvcc, nvprune, libcublas-dev, libcufft, libcusparse.

~ ❯ ls -l /usr/local
total 36
drwxr-xr-x  2 root root 4096 Aug 24 11:48 bin
lrwxrwxrwx  1 root root   22 Aug 24 11:48 cuda -> /etc/alternatives/cuda
lrwxrwxrwx  1 root root   25 Aug 24 11:48 cuda-11 -> /etc/alternatives/cuda-11
drwxr-xr-x 15 root root 4096 Aug 24 11:48 cuda-11.8
drwxr-xr-x  2 root root 4096 Feb 10  2023 etc
drwxr-xr-x  2 root root 4096 Feb 10  2023 games
drwxr-xr-x  2 root root 4096 Feb 10  2023 include
drwxr-xr-x  3 root root 4096 Feb 10  2023 lib
lrwxrwxrwx  1 root root    9 Feb 10  2023 man -> share/man
drwxr-xr-x  2 root root 4096 Feb 10  2023 sbin
drwxr-xr-x  6 root root 4096 Mar  7 17:10 share
drwxr-xr-x  2 root root 4096 Feb 10  2023 src

I'm not entirely sure why there's two separate cuda and cuda-11 folders, and they don't seem to be symlinks to each other. This is a bit concerning, but I'm not going to worry about it too much. My ldconfig -p | grep libcublas points to the /usr/local/cuda variant, but when I check nvcc there, it says the version of the toolkit is 11.8.

Note, however, that it doesn't install cuDNN or TensorRT (aka nvinfer). So let's do that next.

cuDNN and TensorRT

NVIDIA now has a deep learning installation guide here: NVIDIA cuDNN. I personally grabbed cuDNN v8.9.4 for CUDA 11.x, "Local Intaller for Ubuntu22.04 x86_64 (Deb)", and then the rest of the instructions from that linked page worked fine.

Just in case it's unclear, the runtime library installation command was sudo apt-get install libcudnn8=8.9.4.25-1+cuda11.8 (after you've set up the local repository). I didn't install the code samples. After running sudo ldconfig, I was able to find cuDNN using ldconfig -p | grep libcudnn.

For TensorRT, the instructions are a bit confusing but you can basically do the same thing:

~ ❯ sudo dpkg -i nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-11.8_1.0-1_amd64.deb
~ ❯ sudo cp /var/nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-11.8/nv-tensorrt-local-0628887B-keyring.gpg /usr/share/keyrings/

The latter command is the output of the former, so you don't really need to worry about version information - just download the right .deb from the link, and then copy and paste the keyring command.

From here, I installed the full runtime, but not the Python packages - I like to do that inside virtualenvs (since, for example, you might want a different base Python version).

Python packages

Now you can install torch like you always wanted (in a virtualenv, right?):

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

Make sure you check it works!

~ ❯ python -c "import torch; print(torch.cuda.is_available())"
True

Uninstall

I had to temporarily uninstall as part of messing everything up, and it wasn't too bad. Mostly I purged some apt packages using stuff like:

sudo apt-get --purge remove "cuda*"

and swapped cuda for nvidia and nsight.

This gets rid of most things, but as mentioned above, this will keep nvidia-smi around, since that's from the C:\Windows\System32\lxss\lib\ install, which is kept in /usr/lib/wsl/lib/. To remove those, you need to uninstall the NVIDIA graphics driver from your Windows machine (note for me this caused Alacritty to break, but Powershell let me access WSL just fine).

1

As far as can tell! I'm putting this out there and hoping Cunningham's law will get the right answer out, but that depends on you to correct me. Please email me at (fullname) [@] outlook.com.