Getting TensorFlow to recognize your NVIDIA GPU on Windows via WSL2 should be simple based on the official TensorFlow instructions — but for many people, it isn't. After digging through countless unhelpful tutorials and AI-generated suggestions, the real culprit turned out to be simple: TensorFlow couldn't find the NVIDIA libraries it needed.
| Component | Specification |
|---|---|
| 🖥️ CPU | 13th Gen Intel® Core™ i9-13900H (2.60 GHz) |
| 🧠 Memory | 16 GB RAM (15.7 GB usable) |
| 🎮 NVIDIA GPU | GeForce RTX 5060 Laptop GPU (8 GB VRAM) |
| 📺 Integrated GPU | Intel UHD Graphics |
| 🪟 Operating System | Windows 11 Pro 25H2 |
| 🐧 WSL | Ubuntu 24.04 (WSL2) |
✅ Verified: This guide has been tested successfully on the configuration above.
The following benchmark was performed using the tested configuration listed above.
A U-Net–style convolutional neural network with:
- 4 encoder blocks
- Bottleneck with 512 feature maps
- 4 decoder blocks
- Skip connections
- 59-class semantic segmentation output
Input Shape: (input_w=256, input_h=256, input_ch=3)
| Metric | Value |
|---|---|
| Trainable Parameters | 7,724,475 |
| Non-trainable Parameters | 0 |
| Total Parameters | 7,724,475 |
The benchmark measures the average inference time after a warm-up run.
| Device | Average Time / Image | Images / Second |
|---|---|---|
| CPU | (measure) | (measure) |
| NVIDIA RTX 5060 | (measure) | (measure) |
Batch Size: 8
| Device | Time / Epoch |
|---|---|
| CPU | (185 s) |
| NVIDIA RTX 5060 | (9 s) |
Input
├── Encoder
│ ├── Conv2D (32)
│ ├── Conv2D (32)
│ ├── MaxPool
│
│ ├── Conv2D (64)
│ ├── Conv2D (64)
│ ├── MaxPool
│
│ ├── Conv2D (128)
│ ├── Conv2D (128)
│ ├── MaxPool
│
│ ├── Conv2D (256)
│ ├── Conv2D (256)
│ ├── MaxPool
│
│ └── Conv2D (512)
│ Conv2D (512)
│
├── Decoder
│ ├── Conv2DTranspose
│ ├── Skip Connection
│ ├── Conv2D (256)
│ ├── Conv2D (256)
│
│ ├── Conv2DTranspose
│ ├── Skip Connection
│ ├── Conv2D (128)
│ ├── Conv2D (128)
│
│ ├── Conv2DTranspose
│ ├── Skip Connection
│ ├── Conv2D (64)
│ ├── Conv2D (64)
│
│ ├── Conv2DTranspose
│ ├── Skip Connection
│ ├── Conv2D (32)
│ └── Conv2D (32)
│
└── Output
Conv2D (59 classes, Softmax)
Total Parameters: 7,724,475
CPU Train Process
Epoch 1/25
90/90 - 491s - 5s/step - loss: 1.6541 - val_loss: 1.0522
Epoch 2/25
90/90 - 568s - 6s/step - loss: 0.9832 - val_loss: 0.9462
Epoch 3/25
90/90 - 535s - 6s/step - loss: 0.9029 - val_loss: 0.8887
Epoch 4/25
90/90 - 242s - 3s/step - loss: 0.8521 - val_loss: 0.8180
Epoch 5/25
90/90 - 168s - 2s/step - loss: 0.7931 - val_loss: 0.7748
Epoch 6/25
90/90 - 169s - 2s/step - loss: 0.7424 - val_loss: 0.7363
Epoch 7/25
90/90 - 179s - 2s/step - loss: 0.7152 - val_loss: 0.7139
Epoch 8/25
90/90 - 186s - 2s/step - loss: 0.6912 - val_loss: 0.6994
Epoch 9/25
90/90 - 185s - 2s/step - loss: 0.6613 - val_loss: 0.6544
Epoch 10/25
90/90 - 185s - 2s/step - loss: 0.6365 - val_loss: 0.6312
Epoch 11/25
90/90 - 184s - 2s/step - loss: 0.6121 - val_loss: 0.6104
Epoch 12/25
90/90 - 184s - 2s/step - loss: 0.5939 - val_loss: 0.6071
Epoch 13/25
90/90 - 193s - 2s/step - loss: 0.5864 - val_loss: 0.5793
Epoch 14/25
90/90 - 201s - 2s/step - loss: 0.5737 - val_loss: 0.5964
Epoch 15/25
90/90 - 199s - 2s/step - loss: 0.5539 - val_loss: 0.5545
GPU Train Process
Epoch 1/25
90/90 - 99s - 1s/step - loss: 2.0392 - val_loss: 1.0779
Epoch 2/25
90/90 - 9s - 99ms/step - loss: 0.9732 - val_loss: 0.8938
Epoch 3/25
90/90 - 9s - 98ms/step - loss: 0.8790 - val_loss: 0.8433
Epoch 4/25
90/90 - 9s - 98ms/step - loss: 0.8144 - val_loss: 0.7698
Epoch 5/25
90/90 - 9s - 98ms/step - loss: 0.7626 - val_loss: 0.7240
Epoch 6/25
90/90 - 9s - 98ms/step - loss: 0.7158 - val_loss: 0.6753
Epoch 7/25
90/90 - 9s - 99ms/step - loss: 0.6750 - val_loss: 0.6510
Epoch 8/25
90/90 - 9s - 100ms/step - loss: 0.6422 - val_loss: 0.6288
Epoch 9/25
90/90 - 9s - 99ms/step - loss: 0.6225 - val_loss: 0.6063
Epoch 10/25
90/90 - 9s - 99ms/step - loss: 0.5928 - val_loss: 0.5797
Epoch 11/25
90/90 - 9s - 102ms/step - loss: 0.5715 - val_loss: 0.5501
Epoch 12/25
90/90 - 9s - 101ms/step - loss: 0.5600 - val_loss: 0.5531
Epoch 13/25
90/90 - 9s - 102ms/step - loss: 0.5368 - val_loss: 0.5526
Epoch 14/25
90/90 - 9s - 101ms/step - loss: 0.5267 - val_loss: 0.5306
Epoch 15/25
90/90 - 9s - 99ms/step - loss: 0.5068 - val_loss: 0.5397
Note: While these instructions should work on most modern NVIDIA GPUs supported by TensorFlow, they have been specifically verified on the configuration listed above.
This guide documents the exact, working fix — step by step.
Before you start, make sure:
- You have an NVIDIA GPU that is supported by TensorFlow.
- You have correctly installed the NVIDIA driver on Windows.
- You have WSL working on Windows 11.
Note: Newer versions of WSL ship with a more recent Ubuntu release that includes Python 3.14, which can cause compatibility issues. To avoid problems, explicitly install Ubuntu 24.04 rather than the latest available version.
nvidia-smiwsl --install Ubuntu-24.04Then confirm the NVIDIA driver is also visible inside WSL:
nvidia-smisudo apt update
sudo apt install python3-venv python3-pipImportant: create this in your Linux home directory (~), not in /mnt/c/.
cd ~
python3 -m venv tf-gpu(You can name the environment anything — tf-gpu is just an example.)
cd tf-gpu
source bin/activatepip install --upgrade pip
pip install tensorflow[and-cuda]Verify the installation:
python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"This is the step that fixes the "GPU not found" problem for most people:
cd $(dirname $(python -c 'print(__import__("tensorflow").__file__)'))
ln -svf ../nvidia/*/lib/*.so* .
cd -
ln -sf $VIRTUAL_ENV/lib/python3.13/site-packages/nvidia/cuda_nvcc/bin/ptxas $VIRTUAL_ENV/bin/ptxasexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$VIRTUAL_ENV/lib/python3.13/site-packages/tensorflowAdd the LD_LIBRARY_PATH export above to your virtual environment's activate script so it's applied automatically every time you activate tf-gpu.
If this guide helped you, consider starring the repo so others can find it too.