Spaces:
Runtime error
Runtime error
| # Copyright (c) Facebook, Inc. and its affiliates. | |
| # | |
| # This source code is licensed under the MIT license found in the | |
| # LICENSE file in the root directory of this source tree. | |
| # @nolint | |
| # not linting this file because it imports * from swigfaiss, which | |
| # causes a ton of useless warnings. | |
| import numpy as np | |
| from faiss.loader import * | |
| ########################################### | |
| # GPU functions | |
| ########################################### | |
| def index_cpu_to_gpu_multiple_py(resources, index, co=None, gpus=None): | |
| """ builds the C++ vectors for the GPU indices and the | |
| resources. Handles the case where the resources are assigned to | |
| the list of GPUs """ | |
| if gpus is None: | |
| gpus = range(len(resources)) | |
| vres = GpuResourcesVector() | |
| vdev = Int32Vector() | |
| for i, res in zip(gpus, resources): | |
| vdev.push_back(i) | |
| vres.push_back(res) | |
| if isinstance(index, IndexBinary): | |
| return index_binary_cpu_to_gpu_multiple(vres, vdev, index, co) | |
| else: | |
| return index_cpu_to_gpu_multiple(vres, vdev, index, co) | |
| def index_cpu_to_all_gpus(index, co=None, ngpu=-1): | |
| index_gpu = index_cpu_to_gpus_list(index, co=co, gpus=None, ngpu=ngpu) | |
| return index_gpu | |
| def index_cpu_to_gpus_list(index, co=None, gpus=None, ngpu=-1): | |
| """ Here we can pass list of GPU ids as a parameter or ngpu to | |
| use first n GPU's. gpus mut be a list or None. | |
| co is a GpuMultipleClonerOptions | |
| """ | |
| if (gpus is None) and (ngpu == -1): # All blank | |
| gpus = range(get_num_gpus()) | |
| elif (gpus is None) and (ngpu != -1): # Get number of GPU's only | |
| gpus = range(ngpu) | |
| res = [StandardGpuResources() for _ in gpus] | |
| index_gpu = index_cpu_to_gpu_multiple_py(res, index, co, gpus) | |
| return index_gpu | |
| # allows numpy ndarray usage with bfKnn | |
| def knn_gpu(res, xq, xb, k, D=None, I=None, metric=METRIC_L2, device=-1, use_raft=False, vectorsMemoryLimit=0, queriesMemoryLimit=0): | |
| """ | |
| Compute the k nearest neighbors of a vector on one GPU without constructing an index | |
| Parameters | |
| ---------- | |
| res : StandardGpuResources | |
| GPU resources to use during computation | |
| xq : array_like | |
| Query vectors, shape (nq, d) where d is appropriate for the index. | |
| `dtype` must be float32. | |
| xb : array_like | |
| Database vectors, shape (nb, d) where d is appropriate for the index. | |
| `dtype` must be float32. | |
| k : int | |
| Number of nearest neighbors. | |
| D : array_like, optional | |
| Output array for distances of the nearest neighbors, shape (nq, k) | |
| I : array_like, optional | |
| Output array for the nearest neighbors, shape (nq, k) | |
| metric : MetricType, optional | |
| Distance measure to use (either METRIC_L2 or METRIC_INNER_PRODUCT) | |
| device: int, optional | |
| Which CUDA device in the system to run the search on. -1 indicates that | |
| the current thread-local device state (via cudaGetDevice) should be used | |
| (can also be set via torch.cuda.set_device in PyTorch) | |
| Otherwise, an integer 0 <= device < numDevices indicates the GPU on which | |
| the computation should be run | |
| vectorsMemoryLimit: int, optional | |
| queriesMemoryLimit: int, optional | |
| Memory limits for vectors and queries. | |
| If not 0, the GPU will use at most this amount of memory | |
| for vectors and queries respectively. | |
| Vectors are broken up into chunks of size vectorsMemoryLimit, | |
| and queries are broken up into chunks of size queriesMemoryLimit, | |
| including the memory required for the results. | |
| Returns | |
| ------- | |
| D : array_like | |
| Distances of the nearest neighbors, shape (nq, k) | |
| I : array_like | |
| Labels of the nearest neighbors, shape (nq, k) | |
| """ | |
| nq, d = xq.shape | |
| if xq.flags.c_contiguous: | |
| xq_row_major = True | |
| elif xq.flags.f_contiguous: | |
| xq = xq.T | |
| xq_row_major = False | |
| else: | |
| xq = np.ascontiguousarray(xq, dtype='float32') | |
| xq_row_major = True | |
| xq_ptr = swig_ptr(xq) | |
| if xq.dtype == np.float32: | |
| xq_type = DistanceDataType_F32 | |
| elif xq.dtype == np.float16: | |
| xq_type = DistanceDataType_F16 | |
| else: | |
| raise TypeError('xq must be f32 or f16') | |
| nb, d2 = xb.shape | |
| assert d2 == d | |
| if xb.flags.c_contiguous: | |
| xb_row_major = True | |
| elif xb.flags.f_contiguous: | |
| xb = xb.T | |
| xb_row_major = False | |
| else: | |
| xb = np.ascontiguousarray(xb, dtype='float32') | |
| xb_row_major = True | |
| xb_ptr = swig_ptr(xb) | |
| if xb.dtype == np.float32: | |
| xb_type = DistanceDataType_F32 | |
| elif xb.dtype == np.float16: | |
| xb_type = DistanceDataType_F16 | |
| else: | |
| raise TypeError('xb must be float32 or float16') | |
| if D is None: | |
| D = np.empty((nq, k), dtype=np.float32) | |
| else: | |
| assert D.shape == (nq, k) | |
| # interface takes void*, we need to check this | |
| assert D.dtype == np.float32 | |
| D_ptr = swig_ptr(D) | |
| if I is None: | |
| I = np.empty((nq, k), dtype=np.int64) | |
| else: | |
| assert I.shape == (nq, k) | |
| I_ptr = swig_ptr(I) | |
| if I.dtype == np.int64: | |
| I_type = IndicesDataType_I64 | |
| elif I.dtype == I.dtype == np.int32: | |
| I_type = IndicesDataType_I32 | |
| else: | |
| raise TypeError('I must be i64 or i32') | |
| args = GpuDistanceParams() | |
| args.metric = metric | |
| args.k = k | |
| args.dims = d | |
| args.vectors = xb_ptr | |
| args.vectorsRowMajor = xb_row_major | |
| args.vectorType = xb_type | |
| args.numVectors = nb | |
| args.queries = xq_ptr | |
| args.queriesRowMajor = xq_row_major | |
| args.queryType = xq_type | |
| args.numQueries = nq | |
| args.outDistances = D_ptr | |
| args.outIndices = I_ptr | |
| args.outIndicesType = I_type | |
| args.device = device | |
| args.use_raft = use_raft | |
| # no stream synchronization needed, inputs and outputs are guaranteed to | |
| # be on the CPU (numpy arrays) | |
| if vectorsMemoryLimit > 0 or queriesMemoryLimit > 0: | |
| bfKnn_tiling(res, args, vectorsMemoryLimit, queriesMemoryLimit) | |
| else: | |
| bfKnn(res, args) | |
| return D, I | |
| # allows numpy ndarray usage with bfKnn for all pairwise distances | |
| def pairwise_distance_gpu(res, xq, xb, D=None, metric=METRIC_L2, device=-1): | |
| """ | |
| Compute all pairwise distances between xq and xb on one GPU without constructing an index | |
| Parameters | |
| ---------- | |
| res : StandardGpuResources | |
| GPU resources to use during computation | |
| xq : array_like | |
| Query vectors, shape (nq, d) where d is appropriate for the index. | |
| `dtype` must be float32. | |
| xb : array_like | |
| Database vectors, shape (nb, d) where d is appropriate for the index. | |
| `dtype` must be float32. | |
| D : array_like, optional | |
| Output array for all pairwise distances, shape (nq, nb) | |
| metric : MetricType, optional | |
| Distance measure to use (either METRIC_L2 or METRIC_INNER_PRODUCT) | |
| device: int, optional | |
| Which CUDA device in the system to run the search on. -1 indicates that | |
| the current thread-local device state (via cudaGetDevice) should be used | |
| (can also be set via torch.cuda.set_device in PyTorch) | |
| Otherwise, an integer 0 <= device < numDevices indicates the GPU on which | |
| the computation should be run | |
| Returns | |
| ------- | |
| D : array_like | |
| All pairwise distances, shape (nq, nb) | |
| """ | |
| nq, d = xq.shape | |
| if xq.flags.c_contiguous: | |
| xq_row_major = True | |
| elif xq.flags.f_contiguous: | |
| xq = xq.T | |
| xq_row_major = False | |
| else: | |
| raise TypeError( | |
| 'xq matrix should be row (C) or column-major (Fortran)') | |
| xq_ptr = swig_ptr(xq) | |
| if xq.dtype == np.float32: | |
| xq_type = DistanceDataType_F32 | |
| elif xq.dtype == np.float16: | |
| xq_type = DistanceDataType_F16 | |
| else: | |
| xq = np.ascontiguousarray(xb, dtype='float32') | |
| xq_row_major = True | |
| nb, d2 = xb.shape | |
| assert d2 == d | |
| if xb.flags.c_contiguous: | |
| xb_row_major = True | |
| elif xb.flags.f_contiguous: | |
| xb = xb.T | |
| xb_row_major = False | |
| else: | |
| xb = np.ascontiguousarray(xb, dtype='float32') | |
| xb_row_major = True | |
| xb_ptr = swig_ptr(xb) | |
| if xb.dtype == np.float32: | |
| xb_type = DistanceDataType_F32 | |
| elif xb.dtype == np.float16: | |
| xb_type = DistanceDataType_F16 | |
| else: | |
| raise TypeError('xb must be float32 or float16') | |
| if D is None: | |
| D = np.empty((nq, nb), dtype=np.float32) | |
| else: | |
| assert D.shape == (nq, nb) | |
| # interface takes void*, we need to check this | |
| assert D.dtype == np.float32 | |
| D_ptr = swig_ptr(D) | |
| args = GpuDistanceParams() | |
| args.metric = metric | |
| args.k = -1 # selects all pairwise distances | |
| args.dims = d | |
| args.vectors = xb_ptr | |
| args.vectorsRowMajor = xb_row_major | |
| args.vectorType = xb_type | |
| args.numVectors = nb | |
| args.queries = xq_ptr | |
| args.queriesRowMajor = xq_row_major | |
| args.queryType = xq_type | |
| args.numQueries = nq | |
| args.outDistances = D_ptr | |
| args.device = device | |
| # no stream synchronization needed, inputs and outputs are guaranteed to | |
| # be on the CPU (numpy arrays) | |
| bfKnn(res, args) | |
| return D | |