Skip to content

Commit

Permalink
update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
StRigaud committed Nov 21, 2024
1 parent 482d3c4 commit 649c896
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 82 deletions.
29 changes: 14 additions & 15 deletions docs/source/documentation/install.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Installation
############

From package manager (recommended)
From Package Manager (Recommended)
==================================

pyclesperanto is available on PyPI and conda-forge, and can be installed via pip or conda. It is recommended to install it via a package manager to ensure that all dependencies are correctly installed.
Expand All @@ -10,23 +10,23 @@ pyclesperanto is available on PyPI and conda-forge, and can be installed via pip

.. tab:: Pip

install from PyPI with `pip``:
Install from PyPI with `pip`:

.. code-block:: bash
.. code-block:: bash
pip install pyclesperanto
pip install pyclesperanto
.. tab:: Conda

install from conda-forge with `conda` or `mamba`:
Install from conda-forge with `conda` or `mamba`:

.. code-block:: bash
conda install -c conda-forge pyclesperanto
.. note::

It is strongly advised to install pyClesperanto in a virtual environment. For example, you can create a new environment with conda:
It is strongly advised to install pyclesperanto in a virtual environment. For example, you can create a new environment with conda:

.. code-block:: bash
Expand All @@ -35,7 +35,7 @@ pyclesperanto is available on PyPI and conda-forge, and can be installed via pip
.. warning::

mamba or conda install of pyClesperanto on MacOS or Linux will require an additional package to be installed in order to see compatible OpenCL platforms.
Installing pyclesperanto with mamba or conda on MacOS or Linux will require an additional package to be installed to see compatible OpenCL platforms.

.. tabs::

Expand All @@ -51,10 +51,10 @@ pyclesperanto is available on PyPI and conda-forge, and can be installed via pip
conda install -c conda-forge ocl-icd-system
From source
From Source
===========

Alternatively, you can also install the package from source on your system. This is not advised unless you are planning to contribute to the development of the package, test new features or debug issues.
Alternatively, you can install the package from source on your system. This is not advised unless you are planning to contribute to the development of the package, test new features, or debug issues.
We strongly recommend using a virtual environment to install the package from source.

Run the following commands in your terminal to install the package from source:
Expand All @@ -67,19 +67,18 @@ Run the following commands in your terminal to install the package from source:
.. note::

You can add the flag ``-v`` to enables verbose output of the build process.
You can add the flag ``-v`` to enable verbose output of the build process.

.. warning::

The ``-e`` flag is advised if you are planning to contribute to the development of the package.


pyClesperanto should now be installed as a package along with all its dependencies. You can now start using it in your Python scripts and test modifications to the source code.
pyclesperanto should now be installed as a package along with all its dependencies. You can now start using it in your Python scripts and test modifications to the source code.
However, any modification of the source code will require you to re-install the package with `pip` to take effect.

Troubleshooting
===============

In case of error messages such as ``"No OpenCL platform found", you may need to install the OpenCL drivers for your system."`` or ``"clGetPlatformIDs failed: PLATFORM_NOT_FOUND_KHR"``,
you may need to install more recent drivers for your GPU. Or you maybe missing some specific libraries.
If you have issues, contact us for help on the `image.sc forum <https://forum.image.sc/>`__ or creating an issue on the `github repository <https://github.com/clEsperanto/pyclesperanto>`__.
In case of error messages such as ``"No OpenCL platform found"``, you may need to install the OpenCL drivers for your system or ``"clGetPlatformIDs failed: PLATFORM_NOT_FOUND_KHR"``,
you may need to install more recent drivers for your GPU or you may be missing some specific libraries.
If you have issues, contact us for help on the `image.sc forum <https://forum.image.sc/>`__ or create an issue on the `GitHub repository <https://github.com/clEsperanto/pyclesperanto>`__.
115 changes: 56 additions & 59 deletions docs/source/documentation/usage.rst
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
Usage
#####

pyClesperanto is a GPU-accelerated image processing library for Python. The first step is to import the library:
pyClesperanto is a GPU-accelerated image processing library for Python. To get started, import the library:

.. code-block:: python
import pyclesperanto as cle
.. warning::

If an error is thrown at this stage, it is likely that the OpenCL driver is not installed or that you do not have a OpenCL compatible device.
Please, check the installation of your OpenCL and drivers.
If you encounter an error at this stage, it is likely that the OpenCL driver is not installed or that you do not have an OpenCL-compatible device.
Please check the installation of OpenCL and drivers, as well as the compatibility of your system devices with OpenCL.

You can then explore the devices available on your computer with the `list_available_devices()` function or the `info()` function for more details:
Next, you can explore the devices available on your computer using the `list_available_devices()` function or get more detailed information with the `info()` function:

.. code-block:: python
# Return the name of all available devices on the computer
print(cle.list_available_devices())
# Return the name and information of all the devices
# Return the name, index, and information on all the devices
print(cle.info())
If we want to work on a device we first need to select it. By default, the first device found will be automatically selected for conveniency.
You can know which device you currently working on with the `get_device()` function, and you can select another one with `select_device()`:
To work on a specific device, you need to select it.
By default, the last device found will be automatically selected for convenience at import time.
You can check which device you are currently working on with the `get_device()` function, and select another one using the `select_device()` function:

.. code-block:: python
Expand All @@ -41,156 +42,152 @@ You can know which device you currently working on with the `get_device()` funct
Memory transfer
===============

GPU devices have their own memory, which is separated from the computer memory. Therefore, you need to transfer your data to the device memory in order to process it and back to the computer memory to read the results.
This is commonly know as `copy from host to device` and `copy from device to host`. In pyclesperanto we use the functions `push`, `pull`, and `create` to manage the memory transfer.
- `push` is used to transfer data from the host to the device.
- `pull` is used to transfer data from the device to the host.
- `create` is used to allocate an empty space on the device which will be used, for example, to store a result.
GPU devices have their own memory, which is separate from the computer's memory. Therefore, you need to transfer your data to the device memory to process it and back to the computer memory to read the results.
This is commonly known as `copy from host to device` and `copy from device to host`. In pyclesperanto, we use the functions `push`, `pull`, and `create` to manage memory transfer:

These copy operations are costly in term of time as they scale with the data size. Therefore, it is a good practice to avoid them as much as possible once you are opmissing your code.
- `push` is used to transfer/copy data from the host to the device.
- `pull` is used to transfer/copy data from the device to the host.
- `create` is used to allocate empty space on the device, which will be used, for example, to store a result.

These copy operations are costly in terms of time as they scale with the data size. Therefore, it is good practice to avoid them as much as possible once you are optimizing your code.

Create
------

As there is not data transfert, we only need to specify the size of the image we want to create. The image will be created on the GPU and will be empty.
As there is no data transfer, we only need to specify the size of the image we want to create. The image will be created on the GPU and will be empty.
The size of the image is specified as a tuple of integers following the numpy convention ``zyx``.

.. code-block:: python
# create an empty image on the GPU of size 100x100
# Create an empty image on the GPU of size 100x100
gpu_image = cle.create((100, 100))
By default, this will create a 32-bit float space. You can specify the type of the image by passing a ``dtype`` argument:

.. code-block:: python
# create an empty image on the GPU of size 100x100
# Create an empty image on the GPU of size 100x100 with uint8 data type
gpu_image = cle.create((100, 100), dtype=np.uint8)
It is also possible to use an other image as a template to create the new image. This will copy the size and the data type of the template image.
It is also possible to use another image as a template to create the new image. This will copy the size and the data type of the template image.

.. code-block:: python
# create an empty image on the GPU with the same size and data type as the template image
# Create an empty image on the GPU with the same size and data type as the template image
gpu_image = cle.create_like(template_image)
Push
----

The ``push`` will create a memory space on the GPU like ``create`` and then will data array from the host to this new memory space on the device.
The data array is expected to be a numpy array or share the same interface as a numpy array (e.g. dask array).
The ``push`` function will create a memory space on the GPU like ``create`` and then transfer the data array from the host to this new memory space on the device.
The data array is expected to be a numpy array or share the same interface as a numpy array (e.g., dask array).

.. code-block:: python
arr = np.random.random((100, 100)).astype(np.float32)
# push arr to the GPU
# Push arr to the GPU
gpu_image = cle.push(arr)
The data pushed will keep the same data type as the array. Hence, if you push a ``uint8`` array, the data will be stored as ``uint8`` on the GPU.
The array will then use 4 times less memory than if it was stored as ``float32``. This is a good practice to keep in mind when working with GPUs as their
memory can be limited.
The array will then use 4 times less memory than if it was stored as ``float32``. This is a good practice to keep in mind when working with GPUs as their memory can be limited.

.. warning::

pyclesperant does not support `64-bit` data type such as `int64` or `float64` which are the default data type in python. This is to ensure full compatibility with most of the GPU devices.
Hence, precisiion might be lost when converting the data type to `32-bit`.
pyclesperanto does not support `64-bit` data types such as `int64` or `float64`, which are the default data types in Python. This is to ensure full compatibility with most GPU devices.
Hence, precision might be lost when converting the data type to `32-bit`.

Pull
----

Finally, the ``pull`` function will transfer the data from the GPU back to the host. It will be returned has a numpy array.
The ``pull`` function transfers data from the GPU back to the host. It will be returned as a numpy array.

.. code-block:: python
# pull gpu_image to the host
# Pull gpu_image to the host
arr = cle.pull(gpu_image)
The data type of the array will be the same as the data type of the image on the GPU.

Free memory
-----------

Because memory on the GPU can be limited, it can be interesting to free the memory when it is not needed anymore. In pyclesperanto you can free the memory similarly to python with the `del` keyword.
Because memory on the GPU can be limited, it is beneficial to free memory when it is no longer needed. In pyclesperanto, you can free memory similarly to Python using the `del` keyword.

.. code-block:: python
# free the memory of the image on the GPU
# Free the memory of the image on the GPU
del gpu_image
.. warning::

The memory is not freed immediately, but is marked for deletion. The memory will be freed when the garbage collector will run, which in some rare cases can take some time.

Apply an operations on images
=============================
Apply operations on images
==========================

In pyclesperanto, most function are filter or mathematic operation on images. We tried to keep the API as simple as possible with a standard convention for all the functions.
In pyclesperanto, most functions are filters or mathematical operations on images. We tried to keep the API as simple as possible with a standard convention for all the functions.

.. code-block:: python
cle.function_name(input, output, arg0, arg1, ...)
The `output` memory is part of the function signature because GPU cannot allocate memory by itself, you need to specify the output memory space in which it will write the result.
for example, to apply a filter such as a gaussian blur, you need to specify the following code:
The `output` memory is part of the function signature because the GPU cannot allocate memory by itself; you need to specify the output memory space in which it will write the result.
For example, to apply a filter such as a Gaussian blur, you need to specify the following code:

.. code-block:: python
# push an image to the GPU
# Push an image to the GPU
gpu_input = cle.push(cpu_image)
# create an output of the same size of the input
# Create an output of the same size as the input
gpu_output = cle.create(cpu_image.shape)
# apply a gaussian blur with sigma_x=2 and sigma_y=2
# Apply a Gaussian blur with sigma_x=2 and sigma_y=2
cle.gaussian_blur(gpu_input, gpu_output, sigma_x=2, sigma_y=2)
# pull back the result to the host memory
# Pull back the result to the host memory
result = cle.pull(gpu_output)
Eventhough it can be a bit tedious, this code provide a total control on the data and memory being processed.
Now, it is also possible to let pyclesperanto manage some of the memory operation, like the ``push`` and ``create`` of the input and output, making your code shorter.
However we will rely here on default behavior of the functions, which might not be the most efficient in term of memory usage in some cases.
Even though it can be a bit tedious, this code provides total control over the data and memory being processed.
Now, it is also possible to let pyclesperanto manage some of the memory operations, like the ``push`` and ``create`` of the input and output, making your code shorter.
However, we will rely here on the default behavior of the functions, which might not be the most efficient in terms of memory usage in some cases.

.. code-block:: python
# apply a gaussian blur directly on a numpy array and save the result in a pyclesperanto array
# Apply a Gaussian blur directly on a numpy array and save the result in a pyclesperanto array
gpu_output = cle.gaussian_blur(cpu_image, sigma_x=2, sigma_y=2)
# pull back the result to the host
# Pull back the result to the host
result = cle.pull(gpu_output)
Here, the ``cpu_image`` is pushed to the GPU and the output gpu space is created automatically when calling the operation ``gaussian_blur``. The function will return a ``pyclesperanto array``.
Memory transfert are still applied in the background, but the user does not have to worry about it.
Here, the ``cpu_image`` is pushed to the GPU and the output GPU space is created automatically when calling the operation ``gaussian_blur``. The function will return a ``pyclesperanto array``.
Memory transfers are still applied in the background, but the user does not have to worry about it.

Pipeline of operations
======================

Most operation in pyclesperanto are filters. This means that you can chain them together to create a pipeline of operations.
for example, to apply a gaussian blur followed by a threshold, you can write the following code:
Most operations in pyclesperanto are filters. This means that you can chain them together to create a pipeline of operations.
For example, to apply a Gaussian blur followed by a threshold, you can write the following code:

.. code-block:: python
# apply a gaussian blur
# Apply a Gaussian blur
gpu_input = cle.push(cpu_image)
gpu_output = cle.create(cpu_image.shape)
cle.gaussian_blur(gpu_input, gpu_output, sigma_x=2, sigma_y=2)
blurred = cle.pull(gpu_output)
# apply a threshold
# Apply a threshold
gpu_input = cle.push(blurred)
gpu_output = cle.create(blurred.shape)
cle.greater_constant(gpu_output, gpu_output, constant=0.5)
binarized = cle.pull(gpu_output)
Although this code is correct, it is not optimal due to the ``push`` and ``pull`` in between the two operations. This is code is good for protoryping as it allows to inspect the result of each operation.
But in the final version of the code, it is better to chain the operations together to avoid the memory transfert (e.g. ``push`` and ``pull``).
Although this code is correct, it is not optimal due to the ``push`` and ``pull`` in between the two operations. This code is good for prototyping as it allows you to inspect the result of each operation.
But in the final version of the code, it is better to chain the operations together to avoid the memory transfers (e.g., ``push`` and ``pull``).

.. code-block:: python
# apply a gaussian blur
# Apply a Gaussian blur
gpu_blurred = cle.gaussian_blur(cpu_image, sigma_x=2, sigma_y=2)
# apply a threshold
# Apply a threshold
gpu_binarized = cle.greater_constant(gpu_blurred, constant=0.5)
# read the output on host
# Read the output on host
binarized = cle.pull(gpu_binarized)
Here we only use ``push`` at the beginning, inside the ``gaussian_blur`` operation, and ``pull`` at the end of the pipeline when we need to access the data from the CPU.
The ``create`` operation for output data are done automatically inside each operations.
The ``create`` operation for output data is done automatically inside each operation.
20 changes: 14 additions & 6 deletions docs/source/prototype/api_differences.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"pyclesperanto (0.14.2) v.s. pyclespernato_prototype (0.24.4)\n"
"pyclesperanto (0.16.0) v.s. pyclespernato_prototype (0.24.4)\n"
]
}
],
Expand Down Expand Up @@ -405,8 +405,12 @@
" - z_position_of_maximum_z_projection\n",
" - z_position_of_minimum_z_projection\n",
"\n",
"\u001b[1m- Functions in pyclesperanto not in prototype (48):\u001b[0m\n",
"\u001b[1m- Functions in pyclesperanto not in prototype (56):\u001b[0m\n",
" - binary_closing\n",
" - binary_dilate\n",
" - binary_erode\n",
" - binary_infsup\n",
" - binary_opening\n",
" - binary_supinf\n",
" - bottom_hat\n",
" - clic\n",
Expand All @@ -418,9 +422,13 @@
" - connected_components_labeling\n",
" - detect_maxima\n",
" - detect_minima\n",
" - dilate\n",
" - erode\n",
" - dilation\n",
" - erosion\n",
" - filter_label_by_size\n",
" - grayscale_closing\n",
" - grayscale_dilate\n",
" - grayscale_erode\n",
" - grayscale_opening\n",
" - importlib\n",
" - label_bounding_box\n",
" - laplace\n",
Expand Down Expand Up @@ -699,7 +707,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "skbuild3",
"display_name": "skbe",
"language": "python",
"name": "python3"
},
Expand All @@ -713,7 +721,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
"version": "3.12.7"
}
},
"nbformat": 4,
Expand Down
Loading

0 comments on commit 649c896

Please sign in to comment.