diff --git a/README.md b/README.md index 3c5a614..18f1fae 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,291 @@ -# FoundDiff -Official implementation of "FoundDiff: Foundational Diffusion Model for Generalizable Low-Dose CT Denoising" +# FoundDiff - Environment Setup Guide (Working) -## Approach -![](figs/network.png) +## Model Weights +Download the required model weights from: [Google Drive](https://drive.google.com/drive/folders/1B33XyPqC9KkmzmfrCq20-7Xxuf-23PMc?usp=sharing) -## Updates -Feb, 2026: Upload DA-CLIP and FoundDiff model weight (https://drive.google.com/drive/folders/1B33XyPqC9KkmzmfrCq20-7Xxuf-23PMc?usp=sharing) -July, 2025: initial commit. +You will need: +- `DA-CLIP.pth` - Place in `src/` (or as specified in DA-Diff.py) +- `model-400.pt` - Place in `checkpoints/FoundDiff/sample/` +## Quick Setup (Recommended) -## Data Preparation -The 2016 AAPM-Mayo dataset can be downloaded from: [CT Clinical Innovation Center](https://ctcicblog.mayo.edu/2016-low-dose-ct-grand-challenge/) (B30 kernel) -The 2020 AAPM-Mayo dataset can be downloaded from: [cancer imaging archive](https://wiki.cancerimagingarchive.net/pages/viewpage.action?pageId=52758026) +Use the provided `install.yaml` to create the environment: +```bash +conda env create -f install.yaml +conda activate founddiff -## Requirements +# Install pre-built wheels for causal-conv1d and mamba-ssm +pip install causal-conv1d==1.2.2.post1 --no-build-isolation +pip install https://github.com/state-spaces/mamba/releases/download/v2.2.2/mamba_ssm-2.2.2+cu118torch2.1cxx11abiFalse-cp310-cp310-linux_x86_64.whl + +# Verify +python -c "import selective_scan_cuda; print('CUDA kernels loaded successfully!')" ``` + +## System Requirements + - Linux Platform -- torch==1.12.1+cu113 # depends on the CUDA version of your machine -- torchvision==0.13.1+cu113 -- Python==3.8.0 -- numpy==1.22.3 +- NVIDIA GPU with CUDA 11.8+ support +- Python 3.10 + +## Manual Step-by-Step Installation (Alternative) + +### 1. Create Conda Environment + +If you prefer to use the provided install.yaml, skip to step 4 after creating the environment: + +```bash +conda create -n founddiff python=3.10 -y +conda activate founddiff +``` + +### 2. Install PyTorch 2.1.0 with CUDA 11.8 + +```bash +pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118 +pip install "numpy<2" ``` -## Traning and & Inference +### 3. Install CUDA Toolkit 11.8 +**Critical**: Use the specific nvidia channel label to get CUDA 11.8 (not newer versions): -#### Training: +```bash +conda install -c "nvidia/label/cuda-11.8.0" cuda-toolkit -y ``` -CUDA_VISIBLE_DEVICES=1 python train.py --name FoundDiff --is_train --train_num_steps 400000 + +Verify installation: +```bash +nvcc --version +# Should show: CUDA compilation tools, release 11.8, V11.8.89 +``` + +### 4. Install Prerequisites + +```bash +pip install wheel packaging ninja +pip install causal-conv1d==1.2.2.post1 --no-build-isolation +``` + +### 5. Install mamba-ssm (Pre-built Wheel) + +Download and install the pre-built wheel for CUDA 11.8 + Python 3.10: + +```bash +pip install https://github.com/state-spaces/mamba/releases/download/v2.2.2/mamba_ssm-2.2.2+cu118torch2.1cxx11abiFalse-cp310-cp310-linux_x86_64.whl +``` + +### 6. Set Environment Variables + +Create activation script to ensure torch libraries are found: + +```bash +mkdir -p $CONDA_PREFIX/etc/conda/activate.d/ +echo 'export LD_LIBRARY_PATH="$CONDA_PREFIX/lib/python3.10/site-packages/torch/lib:$CONDA_PREFIX/lib:$LD_LIBRARY_PATH"' > $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh +echo 'export CUDA_HOME="$CONDA_PREFIX"' >> $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh +echo 'export PATH="$CONDA_PREFIX/bin:$PATH"' >> $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh ``` -#### Inference & testing: -Put DA-CLIP.pth in src/DA-Diff.py and model-400.pt in checkpoints/FoundDiff/sample +### 7. Verify Installation + +```bash +conda activate founddiff +python -c "import selective_scan_cuda; print('CUDA kernels loaded successfully!')" +``` + +Should output: `CUDA kernels loaded successfully!` + +## Additional Dependencies + +The project requires several Python packages. Install them: + +```bash +pip install kornia einops ipdb pywt accelerate ema-pytorch wandb Augmentor opencv-python lmdb scipy scikit-image matplotlib timm +``` + +Note: Some packages may require additional system dependencies or may have version conflicts. Install them one by one if needed. + +## Running the Project + +### Training + +```bash +conda activate founddiff +CUDA_VISIBLE_DEVICES=1 python train.py --name FoundDiff --is_train --train_num_steps 400000 ``` + +### Inference + +Download the model weights from the Google Drive link above, then run: + +```bash +conda activate founddiff CUDA_VISIBLE_DEVICES=4 python train.py --name FoundDiff --epoch 400 --dataset 2020_seen ``` -Please refer to options files for more setting. +Ensure: +- `DA-CLIP.pth` is placed in `src/` (or as specified in DA-Diff.py) +- `model-400.pt` is placed in `checkpoints/FoundDiff/sample/` + +## Environment Summary + +| Package | Version | Source | +|---------|---------|--------| +| Python | 3.10 | conda | +| PyTorch | 2.1.0+cu118 | pytorch index | +| torchvision | 0.16.0+cu118 | pytorch index | +| numpy | 1.26.x | pip | +| CUDA Toolkit | 11.8.0 | nvidia/label/cuda-11.8.0 | +| causal-conv1d | 1.2.2.post1 | pip (pre-built) | +| mamba-ssm | 2.2.2 | GitHub releases | + +## Data Format and Structure + +### Required Data Format + +The code expects data in **NumPy .npy format** (not PNG, JPG, or DICOM). Each file should be a 2D numpy array of shape (512, 512). + +```python +# How data is loaded in the code (from pdf_dataset.py) +q_data = np.load(self.q_path_list[index]).astype(np.float32) # Low dose CT +f_data = np.load(self.f_path_list[index]).astype(np.float32) # Full dose CT +``` + +### Required Folder Structure + +The code expects data organized in this structure: + +#### For Mayo 2020 Dataset (Testing) + +``` +Mayo2020_ab_2d/test/full_1mm/ # High dose (full dose) - abdominal +Mayo2020_ab_2d/test/quarter_1mm/ # Low dose (1/4 dose) - abdominal + +Mayo2020_lung_2d/test/full_1mm/ # High dose - lung +Mayo2020_lung_2d/test/quarter_1mm/ # Low dose - lung + +Mayo2020_head_2d_2/test/full_1mm/ # High dose - head +Mayo2020_head_2d_2/test/quarter_1mm/ # Low dose - head +``` + +#### For Mayo 2016 Dataset + +``` +Mayo2016_2d/test/full_1mm/ # High dose +Mayo2016_2d/test/quarter_1mm/ # Low dose +``` + +Or alternatively: +``` +Mayo2016_2d/train/full_1mm/ # High dose (training) +Mayo2016_2d/quarter_1mm/ # Low dose +``` + +### Files to Modify for Custom Data Paths + +You need to modify paths in **2 files**: + +#### 1. data/pdf_dataset.py (Lines 331-399) + +Key paths to change: +```python +# Line 331-340: Abdominal data +ab_ndct = sorted_list('/mnt/miah203/zhchen/Mayo2020_ab_2d/'+ phase+'/full_1mm/*')[:num] +ab_dose_1_4_list = sorted_list('/mnt/miah203/zhchen/Mayo2020_ab_2d/'+phase+'/quarter_1mm/*')[start:num:stride] + +# Line 354-363: Lung data +lung_ndct = sorted_list('/mnt/miah203/zhchen/Mayo2020_lung_2d/'+ phase+'/full_1mm/*')[:num] +lung_dose_1_4_list = sorted_list('/mnt/miah203/zhchen/Mayo2020_lung_2d/'+phase+'/quarter_1mm/*')[start:num:stride] + +# Line 382-391: Head data +head_ndct = sorted_list('/mnt/miah203/zhchen/Mayo2020_head_2d_2/'+ phase+'/full_1mm/*')[:num] +head_dose_1_4_list = sorted_list('/mnt/miah203/zhchen/Mayo2020_head_2d_2/'+phase+'/quarter_1mm/*')[start:num:stride] + +# Line 398-399: Mayo2016 data +self.mayo16_ldct = sorted_list('/mnt/miah203/zhchen/Mayo2016_2d/quarter_1mm/*') +self.mayo16_ndct_path_list = sorted_list('/mnt/miah203/zhchen/Mayo2016_2d/train/full_1mm/*') +``` + +#### 2. data/mayo16_dataset.py (Lines 42-49) + +```python +# Line 42-43: Test data paths +self.f_path_list = sorted_list('/mnt/miah203/zhchen/CQ500_2d/test/full_1mm/*') +self.q_path_list = sorted_list('/mnt/miah203/zhchen/CQ500_2d/test/sim-0.25/*') + +# Line 46-48: Training data paths +self.q_path_list = sorted_list('/mnt/miah203/zhchen/Mayo2016_2d/test/quarter_1mm/*') +self.f_path_list = sorted_list('/mnt/miah203/zhchen/Mayo2016_2d/test/full_1mm/*') +``` + +### Example: Setting Custom Data Path + +To use your own data at `/home/user/my_data/`, change the paths in pdf_dataset.py: + +```python +# Before: +ab_ndct = sorted_list('/mnt/miah203/zhchen/Mayo2020_ab_2d/'+ phase+'/full_1mm/*')[:num] + +# After: +ab_ndct = sorted_list('/home/user/my_data/Mayo2020_ab_2d/'+ phase+'/full_1mm/*')[:num] +``` + +### Data Filename Matching + +The code matches low-dose and high-dose files by index: +- Low dose file: `ab-001.npy` → loads from `quarter_1mm/` +- High dose file: `001.npy` → loads from `full_1mm/` using index from filename + +Ensure your low-dose and high-dose files have matching indices in their filenames. + +### Converting DICOM to .npy + +If your data is in DICOM format (.IMA, .dcm), you need to convert it: + +```python +import numpy as np +import pydicom +from PIL import Image +import os + +def dicom_to_npy(dicom_path, output_path): + """Convert DICOM to .npy format""" + ds = pydicom.dcmread(dicom_path) + img = ds.pixel_array + + # Resize to 512x512 if needed + if img.shape != (512, 512): + img = Image.fromarray(img).resize((512, 512)) + img = np.array(img) + + # Normalize to HU values if needed + # img = img * ds.RescaleSlope + ds.RescaleIntercept + + np.save(output_path, img.astype(np.float32)) + +# Example usage: +for f in os.listdir('/path/to/dicom/files'): + if f.endswith('.dcm') or f.endswith('.IMA'): + dicom_to_npy(f, f.replace('.dcm', '.npy')) +``` + +## Troubleshooting + +### "libc10.so: cannot open shared object file" +- Ensure the activation script in Step 6 is created correctly +- Or manually run: `export LD_LIBRARY_PATH="$CONDA_PREFIX/lib/python3.10/site-packages/torch/lib:$CONDA_PREFIX/lib:$LD_LIBRARY_PATH"` + +### "nvcc shows CUDA 13.2" +- You installed cuda-toolkit without specifying the channel label +- Recreate environment and use: `conda install -c "nvidia/label/cuda-11.8.0" cuda-toolkit -y` + +### mamba-ssm compilation fails +- Always use pre-built wheels from GitHub releases +- Building from source requires specific toolchain and is not recommended + +## Credits +- FoundDiff: "Foundational Diffusion Model for Generalizable Low-Dose CT Denoising" +- Mamba SSM: https://github.com/state-spaces/mamba \ No newline at end of file diff --git a/install.yaml b/install.yaml index ca91772..da915e8 100644 --- a/install.yaml +++ b/install.yaml @@ -1,247 +1,40 @@ -name: diffusion +name: founddiff +channels: + - pytorch + - nvidia/label/cuda-11.8.0 + - conda-forge + - defaults dependencies: - - _libgcc_mutex=0.1=main - - _openmp_mutex=5.1=1_gnu - - _pytorch_select=0.1=cpu_0 - - autopep8=2.0.0=pyhd8ed1ab_0 - - blas=1.0=mkl - - brotli=1.0.9=h5eee18b_7 - - brotli-bin=1.0.9=h5eee18b_7 - - brotlipy=0.7.0=py37h27cfd23_1003 - - bzip2=1.0.8=h7b6447c_0 - - ca-certificates=2022.9.24=ha878542_0 - - certifi=2022.9.24=pyhd8ed1ab_0 - - cffi=1.15.1=py37h74dc2b5_0 - - cryptography=38.0.1=py37h9ce1e76_0 - - cuda=11.6.2=0 - - cuda-cccl=11.6.55=hf6102b2_0 - - cuda-command-line-tools=11.6.2=0 - - cuda-compiler=11.6.2=0 - - cuda-cudart=11.6.55=he381448_0 - - cuda-cudart-dev=11.6.55=h42ad0f4_0 - - cuda-cuobjdump=11.6.124=h2eeebcb_0 - - cuda-cupti=11.6.124=h86345e5_0 - - cuda-cuxxfilt=11.6.124=hecbf4f6_0 - - cuda-driver-dev=11.6.55=0 - - cuda-gdb=11.8.86=0 - - cuda-libraries=11.6.2=0 - - cuda-libraries-dev=11.6.2=0 - - cuda-memcheck=11.8.86=0 - - cuda-nsight=11.8.86=0 - - cuda-nsight-compute=11.8.0=0 - - cuda-nvcc=11.6.124=hbba6d2d_0 - - cuda-nvdisasm=11.8.86=0 - - cuda-nvml-dev=11.6.55=haa9ef22_0 - - cuda-nvprof=11.8.87=0 - - cuda-nvprune=11.6.124=he22ec0a_0 - - cuda-nvrtc=11.6.124=h020bade_0 - - cuda-nvrtc-dev=11.6.124=h249d397_0 - - cuda-nvtx=11.6.124=h0630a44_0 - - cuda-nvvp=11.8.87=0 - - cuda-runtime=11.6.2=0 - - cuda-samples=11.6.101=h8efea70_0 - - cuda-sanitizer-api=11.8.86=0 - - cuda-toolkit=11.6.2=0 - - cuda-tools=11.6.2=0 - - cuda-visual-tools=11.6.2=0 - - cudatoolkit=11.0.221=h6bb024c_0 - - cycler=0.11.0=pyhd3eb1b0_0 - - dbus=1.13.18=hb2f20db_0 - - expat=2.4.9=h6a678d5_0 - - ffmpeg=4.3=hf484d3e_0 - - fontconfig=2.14.1=h52c9d5c_1 - - fonttools=4.25.0=pyhd3eb1b0_0 - - freetype=2.12.1=h4a9f257_0 - - gds-tools=1.4.0.31=0 - - giflib=5.2.1=h7b6447c_0 - - glib=2.69.1=h4ff587b_1 - - gmp=6.2.1=h295c915_3 - - gnutls=3.6.15=he1e5248_0 - - gst-plugins-base=1.14.0=h8213a91_2 - - gstreamer=1.14.0=h28cd5cc_2 - - icu=58.2=he6710b0_3 - - idna=3.4=py37h06a4308_0 - - intel-openmp=2021.4.0=h06a4308_3561 - - jpeg=9e=h7f8727e_0 - - kiwisolver=1.4.2=py37h295c915_0 - - krb5=1.19.2=hac12032_0 - - lame=3.100=h7b6447c_0 - - lcms2=2.12=h3be6417_0 - - ld_impl_linux-64=2.38=h1181459_1 - - lerc=3.0=h295c915_0 - - libbrotlicommon=1.0.9=h5eee18b_7 - - libbrotlidec=1.0.9=h5eee18b_7 - - libbrotlienc=1.0.9=h5eee18b_7 - - libclang=10.0.1=default_hb85057a_2 - - libcublas=11.11.3.6=0 - - libcublas-dev=11.11.3.6=0 - - libcufft=10.9.0.58=0 - - libcufft-dev=10.9.0.58=0 - - libcufile=1.4.0.31=0 - - libcufile-dev=1.4.0.31=0 - - libcurand=10.3.0.86=0 - - libcurand-dev=10.3.0.86=0 - - libcusolver=11.4.1.48=0 - - libcusolver-dev=11.4.1.48=0 - - libcusparse=11.7.5.86=0 - - libcusparse-dev=11.7.5.86=0 - - libdeflate=1.8=h7f8727e_5 - - libedit=3.1.20221030=h5eee18b_0 - - libevent=2.1.12=h8f2d780_0 - - libffi=3.3=he6710b0_2 - - libgcc-ng=11.2.0=h1234567_1 - - libgomp=11.2.0=h1234567_1 - - libiconv=1.16=h7f8727e_2 - - libidn2=2.3.2=h7f8727e_0 - - libllvm10=10.0.1=hbcb73fb_5 - - libnpp=11.8.0.86=0 - - libnpp-dev=11.8.0.86=0 - - libnvjpeg=11.9.0.86=0 - - libnvjpeg-dev=11.9.0.86=0 - - libpng=1.6.37=hbc83047_0 - - libpq=12.9=h16c4e8d_3 - - libstdcxx-ng=11.2.0=h1234567_1 - - libtasn1=4.16.0=h27cfd23_0 - - libtiff=4.4.0=hecacb30_2 - - libunistring=0.9.10=h27cfd23_0 - - libuuid=1.41.5=h5eee18b_0 - - libuv=1.40.0=h7b6447c_0 - - libwebp=1.2.4=h11a3e52_0 - - libwebp-base=1.2.4=h5eee18b_0 - - libxcb=1.15=h7f8727e_0 - - libxkbcommon=1.0.1=hfa300c1_0 - - libxml2=2.9.14=h74e7548_0 - - libxslt=1.1.35=h4e12654_0 - - lz4-c=1.9.3=h295c915_1 - - matplotlib=3.5.3=py37h06a4308_0 - - matplotlib-base=3.5.3=py37hf590b9c_0 - - mkl=2021.4.0=h06a4308_640 - - mkl-service=2.4.0=py37h7f8727e_0 - - mkl_fft=1.3.1=py37hd3c417c_0 - - mkl_random=1.2.2=py37h51133e4_0 - - munkres=1.1.4=py_0 - - ncurses=6.3=h5eee18b_3 - - nettle=3.7.3=hbbd107a_1 - - ninja=1.10.2=h06a4308_5 - - ninja-base=1.10.2=hd09550d_5 - - nsight-compute=2022.3.0.22=0 - - nspr=4.33=h295c915_0 - - nss=3.74=h0370c37_0 - - numpy=1.21.5=py37h6c91a56_3 - - numpy-base=1.21.5=py37ha15fc14_3 - - openh264=2.1.1=h4ff587b_0 - - openssl=1.1.1o=h166bdaf_0 - - packaging=21.3=pyhd3eb1b0_0 - - pcre=8.45=h295c915_0 - - pillow=9.2.0=py37hace64e9_1 - - pip=22.2.2=py37h06a4308_0 - - ply=3.11=py37_0 - - pycodestyle=2.9.1=pyhd8ed1ab_0 - - pycparser=2.21=pyhd3eb1b0_0 - - pyopenssl=22.0.0=pyhd3eb1b0_0 - - pyparsing=3.0.9=py37h06a4308_0 - - pyqt=5.15.7=py37h6a678d5_1 - - pyqt5-sip=12.11.0=py37h6a678d5_1 - - pysocks=1.7.1=py37_1 - - python=3.7.9=h7579374_0 - - python-dateutil=2.8.2=pyhd3eb1b0_0 - - pytorch=1.13.0=py3.7_cuda11.6_cudnn8.3.2_0 - - pytorch-cuda=11.6=h867d48c_0 - - pytorch-mutex=1.0=cuda - - qt-main=5.15.2=h327a75a_7 - - qt-webengine=5.15.9=hd2b0992_4 - - qtwebkit=5.212=h4eab89a_4 - - readline=8.2=h5eee18b_0 - - requests=2.28.1=py37h06a4308_0 - - setuptools=65.5.0=py37h06a4308_0 - - sip=6.6.2=py37h6a678d5_0 - - six=1.16.0=pyhd3eb1b0_1 - - sqlite=3.39.3=h5082296_0 - - tk=8.6.12=h1ccaba5_0 - - toml=0.10.2=pyhd3eb1b0_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - torchaudio=0.13.0=py37_cu116 - - torchvision=0.14.0=py37_cu116 - - tornado=6.2=py37h5eee18b_0 - - typing_extensions=4.3.0=py37h06a4308_0 - - urllib3=1.26.12=py37h06a4308_0 - - wheel=0.37.1=pyhd3eb1b0_0 - - xz=5.2.6=h5eee18b_0 - - zlib=1.2.13=h5eee18b_0 - - zstd=1.5.2=ha4553b6_0 + - python=3.10 + - pytorch=2.1.0 + - torchvision=0.16.0 + - numpy<2 + - scipy + - scikit-image + - matplotlib + - pillow + - pywavelets + - lmdb + - ninja + - wheel + - packaging + - pip - pip: - - absl-py==1.4.0 - - accelerate==0.14.0 - - addict==2.4.0 - - astor==0.8.1 - - augmentor==0.2.10 - - cachetools==5.3.0 - - charset-normalizer==2.1.1 - - cloudpickle==2.2.0 - - colorama==0.4.6 - - contextlib2==21.6.0 - - crc32c==2.3.post0 - - diffusers==0.15.1 - - einops==0.6.0 - - ema-pytorch==0.0.10 - - filelock==3.8.0 - - flash-attn==1.0.2 - - future==0.18.2 - - fvcore==0.1.5.post20220512 - - google-auth==2.16.2 - - google-auth-oauthlib==0.4.6 - - grpcio==1.51.3 - - huggingface-hub==0.13.4 - - imageio==2.22.4 - - importlib-metadata==5.0.0 - - iopath==0.1.10 - - joblib==1.2.0 - - json-tricks==3.16.1 - - lmdb==1.4.0 - - markdown==3.4.1 - - markupsafe==2.1.2 - - natsort==8.2.0 - - networkx==2.6.3 - - nni==2.10 - - oauthlib==3.2.2 - - opencv-python==4.7.0.68 - - pandas==1.3.5 - - portalocker==2.6.0 - - prettytable==3.5.0 - - protobuf==3.20.3 - - psutil==5.9.4 - - pyasn1==0.4.8 - - pyasn1-modules==0.2.8 - - pythonwebhdfs==0.2.3 - - pytorch-fid==0.3.0 - - pytorch-warmup==0.1.1 - - pytz==2022.6 - - pywavelets==1.3.0 - - pyyaml==6.0 - - regex==2022.10.31 - - requests-oauthlib==1.3.1 - - responses==0.22.0 - - rsa==4.9 - - schema==0.7.5 - - scikit-image==0.19.3 - - scikit-learn==1.0.2 - - scipy==1.7.3 - - simplejson==3.18.0 - - tabulate==0.9.0 - - tensorboard==2.11.2 - - tensorboard-data-server==0.6.1 - - tensorboard-plugin-wit==1.8.1 - - termcolor==2.1.0 - - tfrecord==1.14.1 - - thop==0.1.1-2209072238 - - threadpoolctl==3.1.0 - - tifffile==2021.11.2 - - timm==0.6.11 - - tqdm==4.64.1 - - typeguard==2.13.3 - - types-toml==0.10.8.1 - - wcwidth==0.2.5 - - websockets==10.4 - - werkzeug==2.2.3 - - yacs==0.1.8 - - zipp==3.10.0 + - einops + - kornia + - timm + - accelerate + - ema-pytorch==0.3.3 + - wandb + - augmentor + - opencv-python + - pydicom + - imageio + - ipdb + +# Note: causal-conv1d and mamba-ssm require pre-built wheels for your CUDA/Python version. +# Install them manually after creating the environment: +# pip install causal-conv1d==1.2.2.post1 --no-build-isolation +# pip install https://github.com/state-spaces/mamba/releases/download/v2.2.2/mamba_ssm-2.2.2+cu118torch2.1cxx11abiFalse-cp310-cp310-linux_x86_64.whl +# +# Or check https://github.com/state-spaces/mamba/releases for the correct wheel for your setup. \ No newline at end of file