diff --git a/docs/source/conf.py b/docs/source/conf.py index 1089f6a5c..5674dda3c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -27,6 +27,7 @@ "sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.doctest", + "sphinxcontrib-osexample", "sphinx.ext.intersphinx", "IPython.sphinxext.ipython_console_highlighting", "IPython.sphinxext.ipython_directive", diff --git a/docs/source/quick_start.md b/docs/source/quick_start.md index 3909b40f2..a1dd31db1 100644 --- a/docs/source/quick_start.md +++ b/docs/source/quick_start.md @@ -1,14 +1,34 @@ # Quick Start -This guide is meant to provide a quick-start tutorial for interacting with RAFT's C++ & Python APIs. +This guide is meant to provide a quick-start primer for using the various different APIs in the cuVS software development kit. -## RAPIDS Memory Manager (RMM) +## Table of Contents -RAFT relies heavily on the [RMM](https://github.com/rapidsai/rmm) library which eases the burden of configuring different allocation strategies globally across the libraries that use it. +- [Resource management](#resource-management) +- [Memory management](#memory-management) +- [Multi-dimensional array formats and interoperability](#multi-dimensional-array-formats-and-interoperability) + - [C++ multi-dimensional span (mdspan)](#c-multi-dimensional-span-mdspan) + - [DLPack](#dlpack) + - [CUDA array interface](#cuda-array-interface) +- [Working with ANN indexes](#working-with-ann-indexes) + - [Building an index](#building-an-index) + - [Searching an index](#searching-an-index) + - [CPU/GPU Interoperability](#cpu-gpu-interoperability) + - [Serializing an index](#serializing-an-index) -## Multi-dimensional Spans and Arrays +------ -Most of the APIs in RAFT accept [mdspan](https://arxiv.org/abs/2010.06474) multi-dimensional array view for representing data in higher dimensions similar to the `ndarray` in the Numpy Python library. RAFT also contains the corresponding owning `mdarray` structure, which simplifies the allocation and management of multi-dimensional data in both host and device (GPU) memory. +## Resource management + +## Memory management + +cuVS relies heavily on the [RMM](https://github.com/rapidsai/rmm) library which eases the burden of configuring different allocation strategies globally across the libraries that use it. + +## Multi-dimensional array formats and interoperability + +### C++ multi-dimensional span (mdspan) + +Most of the C++ APIs in cuVS accept [mdspan](https://arxiv.org/abs/2010.06474) multi-dimensional array view for representing data in higher dimensions similar to the `ndarray` in the Numpy Python library. RAFT also contains the corresponding owning `mdarray` structure, which simplifies the allocation and management of multi-dimensional data in both host and device (GPU) memory. The `mdarray` is an owning object that forms a convenience layer over RMM and can be constructed in RAFT using a number of different helper functions: @@ -23,7 +43,7 @@ auto vector = raft::make_device_vector(handle, n_cols); auto matrix = raft::make_device_matrix(handle, n_rows, n_cols); ``` -The `mdspan` is a lightweight non-owning view that can wrap around any pointer, maintaining shape, layout, and indexing information for accessing elements. +The `mdspan` is a lightweight non-owning view that can wrap around any pointer, maintaining shape, layout, and indexing information for accessing elements. We can construct `mdspan` instances directly from the above `mdarray` instances: @@ -89,95 +109,16 @@ int stride = 10; auto vector = raft::make_device_vector_view(vector_ptr, raft::make_vector_strided_layout(n_elements, stride)); ``` +### DLPack -## C++ Example - -Most of the primitives in RAFT accept a `raft::handle_t` object for the management of resources which are expensive to create, such CUDA streams, stream pools, and handles to other CUDA libraries like `cublas` and `cusolver`. - -The example below demonstrates creating a RAFT handle and using it with `device_matrix` and `device_vector` to allocate memory, generating random clusters, and computing -pairwise Euclidean distances: - -```c++ -#include -#include -#include -#include - -raft::handle_t handle; - -int n_samples = 5000; -int n_features = 50; - -auto input = raft::make_device_matrix(handle, n_samples, n_features); -auto labels = raft::make_device_vector(handle, n_samples); -auto output = raft::make_device_matrix(handle, n_samples, n_samples); - -raft::random::make_blobs(handle, input.view(), labels.view()); - -auto metric = raft::distance::DistanceType::L2SqrtExpanded; -raft::distance::pairwise_distance(handle, input.view(), input.view(), output.view(), metric); -``` - -## Python Example - -The `pylibraft` package contains a Python API for RAFT algorithms and primitives. `pylibraft` integrates nicely into other libraries by being very lightweight with minimal dependencies and accepting any object that supports the `__cuda_array_interface__`, such as [CuPy's ndarray](https://docs.cupy.dev/en/stable/user_guide/interoperability.html#rmm). The number of RAFT algorithms exposed in this package is continuing to grow from release to release. - -The example below demonstrates computing the pairwise Euclidean distances between CuPy arrays. Note that CuPy is not a required dependency for `pylibraft`. - -```python -import cupy as cp - -from pylibraft.distance import pairwise_distance - -n_samples = 5000 -n_features = 50 - -in1 = cp.random.random_sample((n_samples, n_features), dtype=cp.float32) -in2 = cp.random.random_sample((n_samples, n_features), dtype=cp.float32) - -output = pairwise_distance(in1, in2, metric="euclidean") -``` - -The `output` array in the above example is of type `raft.common.device_ndarray`, which supports [__cuda_array_interface__](https://numba.pydata.org/numba-doc/dev/cuda/cuda_array_interface.html#cuda-array-interface-version-2) making it interoperable with other libraries like CuPy, Numba, and PyTorch that also support it. CuPy supports DLPack, which also enables zero-copy conversion from `raft.common.device_ndarray` to JAX and Tensorflow. - -Below is an example of converting the output `pylibraft.common.device_ndarray` to a CuPy array: -```python -cupy_array = cp.asarray(output) -``` +### CUDA array interface -And converting to a PyTorch tensor: -```python -import torch +## Working with ANN indexes -torch_tensor = torch.as_tensor(output, device='cuda') -``` +### Building an index -When the corresponding library has been installed and available in your environment, this conversion can also be done automatically by all RAFT compute APIs by setting a global configuration option: -```python -import pylibraft.config -pylibraft.config.set_output_as("cupy") # All compute APIs will return cupy arrays -pylibraft.config.set_output_as("torch") # All compute APIs will return torch tensors -``` - -You can also specify a `callable` that accepts a `pylibraft.common.device_ndarray` and performs a custom conversion. The following example converts all output to `numpy` arrays: -```python -pylibraft.config.set_output_as(lambda device_ndarray: return device_ndarray.copy_to_host()) -``` - - -`pylibraft` also supports writing to a pre-allocated output array so any `__cuda_array_interface__` supported array can be written to in-place: +### Searching an index -```python -import cupy as cp +### CPU/GPU interoperability -from pylibraft.distance import pairwise_distance - -n_samples = 5000 -n_features = 50 - -in1 = cp.random.random_sample((n_samples, n_features), dtype=cp.float32) -in2 = cp.random.random_sample((n_samples, n_features), dtype=cp.float32) -output = cp.empty((n_samples, n_samples), dtype=cp.float32) - -pairwise_distance(in1, in2, out=output, metric="euclidean") -``` +### Serializing an index \ No newline at end of file