A TensorFlow GPU failure often appears as a clean import followed by an empty device list from tf.config.list_physical_devices('GPU'). That symptom means Python is running TensorFlow, but the active environment has not connected TensorFlow to an NVIDIA GPU runtime.
The current pip GPU path depends on the host NVIDIA driver reporting the device, a supported Linux x86_64 or WSL2 target, and the packaged CUDA libraries installed into the active Python environment through tensorflow[and-cuda]. Fix the layer that fails first instead of reinstalling TensorFlow repeatedly.
Native Windows GPU support ended after TensorFlow 2.10, and current macOS packages do not provide the official CUDA path. On a supported Linux or WSL2 system where nvidia-smi works, the common virtual-environment repair is to refresh the GPU package, add TensorFlow's NVIDIA library symlinks, add the ptxas symlink, and retest the original empty device list.
$ source ~/venvs/tf-gpu/bin/activate (tf-gpu) $
Use the equivalent conda activate tf-gpu command for a Conda-managed environment.
Related: How to create a virtual environment for TensorFlow
Related: How to create a Conda environment for TensorFlow
(tf-gpu) $ python -c "import tensorflow as tf; print(tf.__version__); print(tf.config.list_physical_devices('GPU'))"
2.21.0
[]
An empty list confirms TensorFlow imported but did not expose a physical GPU to Python.
Related: How to check the TensorFlow version
(tf-gpu) $ nvidia-smi Mon Jun 29 04:26:18 2026 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 575.64.03 Driver Version: 575.64.03 CUDA Version: 12.9 | |-----------------------------------------+------------------------+----------------------| | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | 0 NVIDIA RTX 4080 SUPER Off | 00000000:01:00.0 Off | Off | ##### snipped #####
If nvidia-smi fails or shows no GPU, repair the host driver or WSL2 GPU passthrough before changing Python packages. The TensorFlow package cannot replace a missing kernel driver.
(tf-gpu) $ uname -m x86_64
Use the current pip GPU path on Linux x86_64 or WSL2. Current native Windows and macOS packages do not expose CUDA GPUs for new TensorFlow releases.
(tf-gpu) $ python -m pip install --upgrade "tensorflow[and-cuda]" Requirement already satisfied: tensorflow in /home/user/venvs/tf-gpu/lib/python3.12/site-packages (2.21.0) Collecting nvidia-cudnn-cu12<10.0,>=9.3.0.75 ##### snipped ##### Successfully installed keras-3.14.0 nvidia-cudnn-cu12-9.21.0.82 tensorflow-2.21.0
The and-cuda extra installs the NVIDIA user-space packages into the active environment. It still depends on a working host driver.
Related: How to install TensorFlow with pip
(tf-gpu) $ python -c "import tensorflow as tf; print(tf.__file__)" /home/user/venvs/tf-gpu/lib/python3.12/site-packages/tensorflow/__init__.py
(tf-gpu) $ pushd $(dirname $(python -c 'print(__import__("tensorflow").__file__)'))
~/venvs/tf-gpu/lib/python3.12/site-packages/tensorflow ~/project
(tf-gpu) $ ln -svf ../nvidia/*/lib/*.so* .
'./libcudart.so.12' -> '../nvidia/cuda_runtime/lib/libcudart.so.12'
##### snipped #####
(tf-gpu) $ popd
~/project
This follows TensorFlow's current virtual-environment repair for GPU tests that fail because packaged CUDA components are not discovered automatically.
(tf-gpu) $ ln -sf $(find $(dirname $(dirname $(python -c "import nvidia.cuda_nvcc; print(nvidia.cuda_nvcc.__file__)"))/*/bin/) -name ptxas -print -quit) $VIRTUAL_ENV/bin/ptxas
For Conda, replace $VIRTUAL_ENV/bin/ptxas with the active environment's bin/ptxas path when $VIRTUAL_ENV is empty.
(tf-gpu) $ python -c "import tensorflow as tf;print(tf.config.list_physical_devices('GPU'))"
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
If the list remains empty after nvidia-smi works and the symlinks are in place, rebuild the environment from a supported Python interpreter and the current pip GPU package instead of mixing system CUDA paths into the environment.
Related: How to build a TensorFlow GPU environment
(tf-gpu) $ python -c "import tensorflow as tf; print(tf.matmul(tf.ones((128, 128)), tf.ones((128, 128))).device)" /job:localhost/replica:0/task:0/device:GPU:0
After the device path reports GPU:0, configure memory growth if the process should avoid reserving most GPU memory at startup.
Related: How to enable TensorFlow GPU memory growth