diff --git a/notebooks/ivf_flat_example.ipynb b/notebooks/ivf_flat_example.ipynb new file mode 100644 index 0000000000..35f63f901d --- /dev/null +++ b/notebooks/ivf_flat_example.ipynb @@ -0,0 +1,660 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4f49c5c4-1170-42a7-9d6a-b90acd00c3c3", + "metadata": {}, + "source": [ + "# RAFT IVF Flat" + ] + }, + { + "cell_type": "markdown", + "id": "4bcfe810-f120-422c-b2bb-72cc43d0c4ca", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "This notebook demonstrates how to run approximate nearest neighbor search using the IVF-Flat algorithm." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "fe73ada7-7b7f-4005-9440-85428194311b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import cupy as cp\n", + "import numpy as np\n", + "from pylibraft.common import DeviceResources\n", + "from pylibraft.neighbors import ivf_flat\n", + "import time\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5350e4d9-0993-406a-80af-29538b5677c2", + "metadata": {}, + "outputs": [], + "source": [ + "import rmm\n", + "from rmm.allocators.cupy import rmm_cupy_allocator\n", + "mr = rmm.mr.PoolMemoryResource(\n", + " rmm.mr.CudaMemoryResource(),\n", + " initial_pool_size=2**30\n", + ")\n", + "rmm.mr.set_current_device_resource(mr)\n", + "cp.cuda.set_allocator(rmm_cupy_allocator)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5daa4b4-96de-4e74-bfd6-505b13595f62", + "metadata": {}, + "outputs": [], + "source": [ + "# Report the GPU in us\n", + "!nvidia-smi" + ] + }, + { + "cell_type": "markdown", + "id": "104ef64f-7d98-4450-b04b-fcf498099b4b", + "metadata": {}, + "source": [ + "### Utility functions" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "496fc8a6-139f-4b88-a2f4-a34357fd1712", + "metadata": {}, + "outputs": [], + "source": [ + "def memmap_bin_file(bin_file, dtype, shape=None):\n", + " if bin_file is None:\n", + " return None\n", + " a = np.memmap(bin_file, mode=\"r\", dtype=\"uint32\", shape=(2,))\n", + " if shape is None:\n", + " shape = (a[0], a[1])\n", + " # print('# {}: shape: {}, dtype: {}'.format(bin_file, shape, dtype))\n", + " return np.memmap(bin_file, mode=\"r\", dtype=dtype, offset=8, shape=shape)\n", + "\n", + "\n", + "def calc_recall(ann_idx, true_nn_idx):\n", + " ann_idx = np.asarray(ann_idx)\n", + " if ann_idx.shape != true_nn_idx.shape:\n", + " raise RuntimeError(\n", + " \"Incompatible shapes {} vs {}\".format(ann_idx.shape, true_nn_idx.shape)\n", + " )\n", + " n = 0\n", + " for i in range(ann_idx.shape[0]):\n", + " n += np.intersect1d(ann_idx[i, :], true_nn_idx[i, :]).size\n", + " recall = n / ann_idx.size\n", + " return recall\n", + "\n", + "class BenchmarkTimer:\n", + " \"\"\"Provides a context manager that runs a code block `reps` times\n", + " and records results to the instance variable `timings`. Use like:\n", + " .. code-block:: python\n", + " timer = BenchmarkTimer(rep=5)\n", + " for _ in timer.benchmark_runs():\n", + " ... do something ...\n", + " print(np.min(timer.timings))\n", + "\n", + " This class is part of the rapids/cuml benchmark suite\n", + " \"\"\"\n", + "\n", + " def __init__(self, reps=1, warmup=0):\n", + " self.warmup = warmup\n", + " self.reps = reps\n", + " self.timings = []\n", + "\n", + " def benchmark_runs(self):\n", + " for r in range(self.reps + self.warmup):\n", + " t0 = time.time()\n", + " yield r\n", + " t1 = time.time()\n", + " self.timings.append(t1 - t0)\n", + " if r >= self.warmup:\n", + " self.timings.append(t1 - t0)" + ] + }, + { + "cell_type": "markdown", + "id": "eee226b2-7110-42da-b022-385ee7462ed0", + "metadata": {}, + "source": [ + "## Load dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ba75cbad-1bf0-4c07-b130-c34d4e51410f", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO use a smaller dataset and dataset loader\n", + "k = 10\n", + "\n", + "dtype=np.float32\n", + "\n", + "dataset_dirname = \"/workspace/rapids/gh/data/deep-1B\"\n", + "\n", + "dataset_filename = os.path.join(dataset_dirname, \"base.10M.fbin\")\n", + "queries_filename = os.path.join(dataset_dirname, \"query.public.10K.fbin\")\n", + "\n", + "# groundthruth filenames\n", + "dataset_dirname = \"/workspace/rapids/gh/data/deep-10M\"\n", + "gt_indices_filename = os.path.join(dataset_dirname, \"groundtruth.neighbors.ibin\")\n", + "gt_dist_filename = os.path.join(dataset_dirname, \"groundtruth.distances.fbin\")\n", + "\n", + "dataset_np = memmap_bin_file(dataset_filename, dtype)\n", + "dataset = cp.asarray(dataset_np)\n", + "\n", + "n_samples = dataset.shape[0]\n", + "n_features = dataset.shape[1]\n", + "\n", + "queries = np.asarray(memmap_bin_file(queries_filename, dtype))\n", + "\n", + "gt_indices_100 = memmap_bin_file(gt_indices_filename, dtype=np.int32)\n", + "gt_distances_100 = memmap_bin_file(gt_dist_filename, dtype=np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "61a4c327-800a-4b8d-a978-37ec80d4dfad", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dataset shape=(10000000,96), dtype=, size= 3.6 GiB\n" + ] + } + ], + "source": [ + "itemsize = np.dtype(dtype).itemsize \n", + "total_size = n_samples * n_features * itemsize / (1<<30)\n", + "print(\"Dataset shape=({0},{1}), dtype={2}, size={3:6.1f} GiB\".format(n_samples, n_features, dtype, total_size))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "84ca624a-9ced-4083-9bdd-9438cfff16f4", + "metadata": {}, + "outputs": [], + "source": [ + "# we need only k columns from the groundthruth files\n", + "gt_indices = np.asarray(gt_indices_100[:, :k])\n", + "gt_distances = np.asarray(gt_distances_100[:, :k])" + ] + }, + { + "cell_type": "markdown", + "id": "9f463c50-d1d3-49be-bcfe-952602efa603", + "metadata": {}, + "source": [ + "## Build index" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "737f8841-93f9-4c8e-b2e1-787d4474ef94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 315 ms, sys: 21.9 ms, total: 337 ms\n", + "Wall time: 334 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "#handle = Handle()\n", + "\n", + "# see documentation https://github.com/rapidsai/raft/blob/082be6ecd4437d180bf34d5ba5d691a27b21141f/python/pylibraft/pylibraft/neighbors/ivf_flat/ivf_flat.pyx#L77-L124\n", + "build_params = ivf_flat.IndexParams(\n", + " n_lists=1024,\n", + " metric=\"sqeuclidean\",\n", + " kmeans_trainset_fraction=0.1,\n", + " kmeans_n_iters=20,\n", + " add_data_on_build=True\n", + " )\n", + "\n", + "index = ivf_flat.build(build_params, dataset)#, handle=handle)" + ] + }, + { + "cell_type": "markdown", + "id": "a16a0cf6-3b05-4afd-9bb8-54431e0d7439", + "metadata": {}, + "source": [ + "The index is built. We can print some basic information of the index" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1aec7024-6e5d-4d2c-82e6-7b5734aec958", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(type=IVF-FLAT, metric=sqeuclidean, size=10000000, dim=96, n_lists=1024, adaptive_centers=False)\n" + ] + } + ], + "source": [ + "print(index)" + ] + }, + { + "cell_type": "markdown", + "id": "df7d4958-56a3-48ea-bd64-3486fdb57fb7", + "metadata": {}, + "source": [ + "## Search neighbors" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "ebfc0980-32a8-480e-bdc0-7a5472bbfb6b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(10000, 96)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "queries.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "46e0421b-9335-47a2-8451-a91f56c2f086", + "metadata": {}, + "outputs": [], + "source": [ + "handle = DeviceResources()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "595454e1-7240-4b43-9a73-963d5670b00c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 386 ms, sys: 209 ms, total: 594 ms\n", + "Wall time: 590 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "n_queries=10000\n", + "handle = DeviceResources()\n", + "# n_probes is the number of clusters we select in the first (coarse) search step. This is the only hyper parameter for search.\n", + "search_params = ivf_flat.SearchParams(n_probes=50)\n", + "\n", + "# Search 10 nearest neighbors.\n", + "distances, indices = ivf_flat.search(search_params, index, cp.asarray(queries[:n_queries,:]), k=10, handle=handle)\n", + " \n", + "handle.sync()\n", + "distances, neighbors = cp.asnumpy(distances), cp.asnumpy(indices)" + ] + }, + { + "cell_type": "markdown", + "id": "43d20ca7-7b9e-4046-bb52-640a2744db75", + "metadata": {}, + "source": [ + "The returnad arrays have shappe {n_queries x 10] and store the distance values and the indices of the searched vectors." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "8cd9cd20-ca00-4a35-a0a0-86636521b31a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.99419" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "calc_recall(neighbors, gt_indices)" + ] + }, + { + "cell_type": "markdown", + "id": "cde5079c-9777-45a1-9545-cffbcc59988f", + "metadata": {}, + "source": [ + "## Save and load the index" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "bf94e45c-e7fb-4aa3-a611-ddaee7ac41ae", + "metadata": {}, + "outputs": [], + "source": [ + "ivf_flat.save(\"my_ivf_flat_index.bin\", index)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "1622d9be-be41-4d25-be99-d348c5e54957", + "metadata": {}, + "outputs": [], + "source": [ + "index = ivf_flat.load(\"my_ivf_flat_index.bin\")" + ] + }, + { + "cell_type": "markdown", + "id": "15d503e5-05e8-47ce-8501-e13fc512099c", + "metadata": {}, + "source": [ + "## Tune search parameters\n", + "Search has a single hyper parameter: n_probes, which describes how many neighboring cluster is searched (probed) for each query. Within a probed cluster, we compute the distance between all the vectors in the cluster and the query point, and select the top-k neighbors. Finally, we consider all the neighbor candidates from the probed clusters, and select top-k out of them." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "07b89052-c41d-464e-9cd3-cf1f1fb16b32", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(type=IVF-FLAT, metric=sqeuclidean, size=10000000, dim=96, n_lists=1024, adaptive_centers=False)\n" + ] + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "ace0c31f-af75-4352-a438-123a9a03612c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Benchmarking search with n_probes= 10\n", + "recall 0.93047\n", + "Average search time: 0.081 +/- 0.0559 s\n", + "Queries per second (QPS): 123637\n", + "\n", + "Benchmarking search with n_probes= 50\n", + "recall 0.99419\n", + "Average search time: 0.391 +/- 0.276 s\n", + "Queries per second (QPS): 25587\n", + "\n", + "Benchmarking search with n_probes= 100\n", + "recall 0.99842\n", + "Average search time: 0.774 +/- 0.546 s\n", + "Queries per second (QPS): 12927\n", + "\n", + "Benchmarking search with n_probes= 200\n", + "recall 0.99941\n", + "Average search time: 1.521 +/- 1.07 s\n", + "Queries per second (QPS): 6575\n", + "\n", + "Benchmarking search with n_probes= 500\n", + "recall 0.99956\n", + "Average search time: 3.756 +/- 2.66 s\n", + "Queries per second (QPS): 2662\n", + "\n", + "Benchmarking search with n_probes= 1000\n", + "recall 0.99957\n", + "Average search time: 6.897 +/- 4.88 s\n", + "Queries per second (QPS): 1450\n" + ] + } + ], + "source": [ + "n_probes = np.asarray([10, 50, 100, 200, 500, 1000]);\n", + "qps = np.zeros(n_probes.shape);\n", + "recall = np.zeros(n_probes.shape);\n", + "\n", + "for i in range(len(n_probes)):\n", + " print(\"\\nBenchmarking search with n_probes=\", n_probes[i])\n", + " timer = BenchmarkTimer(reps=1, warmup=1)\n", + " for rep in timer.benchmark_runs():\n", + " distances, neighbors = ivf_flat.search(\n", + " ivf_flat.SearchParams(n_probes=n_probes[i]),\n", + " index,\n", + " cp.asarray(queries),\n", + " k,\n", + " handle=handle,\n", + " )\n", + " \n", + " recall[i] = calc_recall(cp.asnumpy(neighbors), gt_indices)\n", + " print(\"recall\", recall[i])\n", + "\n", + " timings = np.asarray(timer.timings)\n", + " avg_time = timings.mean()\n", + " std_time = timings.std()\n", + " qps[i] = queries.shape[0] / avg_time\n", + " print(\"Average search time: {0:7.3f} +/- {1:7.3} s\".format(avg_time, std_time))\n", + " print(\"Queries per second (QPS): {0:8.0f}\".format(qps[i]))" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "e1ac370f-91c8-4054-95c7-a749df5f16d2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure(figsize=(12,3))\n", + "ax = fig.add_subplot(131)\n", + "ax.plot(n_probes, recall,'o-')\n", + "#ax.set_xticks(bench_k, bench_k)\n", + "ax.set_xlabel('n_probes')\n", + "ax.grid()\n", + "ax.set_ylabel('recall (@k=10)')\n", + "\n", + "ax = fig.add_subplot(132)\n", + "ax.plot(n_probes, qps,'o-')\n", + "#ax.set_xticks(bench_k, bench_k)\n", + "ax.set_xlabel('n_probes')\n", + "ax.grid()\n", + "ax.set_ylabel('queries per second');\n", + "\n", + "ax = fig.add_subplot(133)\n", + "ax.plot(recall, qps,'o-')\n", + "#ax.set_xticks(bench_k, bench_k)\n", + "ax.set_xlabel('recall')\n", + "ax.grid()\n", + "ax.set_ylabel('queries per second');\n", + "#ax.set_yscale('log')" + ] + }, + { + "cell_type": "markdown", + "id": "81e7ad6a-bddc-45de-9cce-0fb913f91efe", + "metadata": {}, + "source": [ + "## Adjust build parameters\n", + "### n_clusters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "addbfff3-7773-4290-9608-5489edf4886d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "0c44800f-1e9e-4f7b-87fe-0f25e6590faa", + "metadata": {}, + "source": [ + "### trainset fraction" + ] + }, + { + "cell_type": "markdown", + "id": "f9d343c8-a295-4f31-8a3a-3ead9d26f50f", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "25289ebc-7d89-4fa6-bc62-e25b6e77750c", + "metadata": {}, + "source": [ + "### add vectors on build\n", + "Currently we cannot configure how RAFT sub-samples the input. If we want to have a fine control on how we select the training set, then we can create the index in two steps:\n", + "1. Define cluster centers on a training set, but do not add any vector to the index\n", + "2. add vectors to the index (extend)\n", + "\n", + "- The second step is familiar for faiss users.\n", + "- Note that raft does not require adding the data in batches. We do internal batching. If the user prefers, can use your own batching.\n", + "- We have an option in controlling whether the cluster centers should be recalculated.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "7ebcf970-94ed-4825-9885-277bd984b90c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(type=IVF-FLAT, metric=sqeuclidean, size=10000000, dim=96, n_lists=1024, adaptive_centers=False)" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "build_params = ivf_flat.IndexParams(\n", + " n_lists=1024,\n", + " metric=\"sqeuclidean\",\n", + " kmeans_trainset_fraction=1,\n", + " kmeans_n_iters=20,\n", + " add_data_on_build=False\n", + " )\n", + "\n", + "n_train = 10000\n", + "train_set = dataset[cp.random.choice(dataset.shape[0], n_train, replace=False),:]\n", + "index = ivf_flat.build(build_params, train_set)\n", + "ivf_flat.extend(index, dataset, cp.arange(dataset.shape[0], dtype=cp.int64))" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "42c70329-1a35-4d11-8688-087de8a637c1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10000000" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index.size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "029d48a9-baf7-4263-af43-9e500ef3cce4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}